Qml Listview在重置模型时保留视图 我有一个QML ListVIEW,它有一个C++模型。数据是从另一个线程生成的,并在C++代码中更新为模型。之后,我使用BeginResetModel()更新qml中的listview。除qml中的视图外,所有内容都可以从一开始就运行,但我希望listview保持当前视图而不更改视图

Qml Listview在重置模型时保留视图 我有一个QML ListVIEW,它有一个C++模型。数据是从另一个线程生成的,并在C++代码中更新为模型。之后,我使用BeginResetModel()更新qml中的listview。除qml中的视图外,所有内容都可以从一开始就运行,但我希望listview保持当前视图而不更改视图,c++,listview,qt5,C++,Listview,Qt5,MWE: listviewelement.cpp ListViewElement::ListViewElement(int id,QString attr):m_id(id),m_attr(attr) { } int ListViewElement::getId() { return m_id; } QString ListViewElement::getAttr() { return m_attr; } listviewmodel.cpp ListViewModel::

MWE:

listviewelement.cpp

ListViewElement::ListViewElement(int id,QString attr):m_id(id),m_attr(attr)
{

}

int ListViewElement::getId()
{
    return m_id;
}

QString ListViewElement::getAttr()
{
    return m_attr;
}
listviewmodel.cpp

ListViewModel::ListViewModel(QObject *parent): QAbstractListModel(parent)
  , m_items(new QList<ListViewElement*>()){

}


QHash<int,QByteArray> ListViewModel::roleNames() const
{
    qDebug() << Q_FUNC_INFO;
    QHash<int,QByteArray> roles;
    roles[ListViewEnum::ID] = "id";
    roles[ListViewEnum::ATTR] = "attr";
    return roles;
}

QVariant ListViewModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() > m_items->size()-1)
        return QVariant();

    ListViewElement *dobj = m_items->at(index.row());

    if (!dobj)
        return QVariant();

    switch (role) {
    case ListViewEnum::ID:
        return QVariant::fromValue(dobj->getId());
    case ListViewEnum::ATTR:
        return QVariant::fromValue(dobj->getAttr());
    default:
        return QVariant();
    }
}

int ListViewModel::rowCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return m_items? m_items->size(): 0;
}

void ListViewModel::generateData()
{
    ListViewElement *ele = new ListViewElement(1,"attribute");
    m_items->append(ele);
    beginResetModel();
    endResetModel();
}

从我所看到的,我有几个建议,虽然我没有测试它,所以它可能有效,也可能无效

  • 我看到您只添加了数据,那么当您可以逐个插入行并使用
    beginInsertRows()和endInsertRows()方法进行插入时,为什么要重置模型呢
  • 如果这没有帮助,您可以在QML中连接到模型的
    modelAboutToBeReset()
    信号(为此在modelAboutToBeReset上编写一个处理程序
    ),并在重置之前保存当前索引,然后在重置模型之后,使用处理程序
    onModelReset
    通过调用
    listview的“positionviewatinex(index,mode)”方法将listview定位到此索引中

另外,您必须在调用
beginResetModel()
endResetModel()

之间更改型号,谢谢您的回答。在这个示例中,我只插入一行,但列表可以添加多行,然后再排序,因此我需要
resetModel
。事实上,我试图确定的新位置并使用
positionviewatinex
,但它不起作用
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "listviewmodel.h"
#include <QQmlContext>
#include <QTimer>

int main(int argc, char *argv[])
{
    ListViewModel model;
    QTimer *timer = new QTimer();
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;
    engine.rootContext()->setContextProperty("listViewModel",&model);
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    QObject::connect(timer,SIGNAL(timeout()),&model,SLOT(generateData()));

    timer->start(1000);
    return app.exec();
}
import QtQuick 2.5
import QtQuick.Window 2.2

Window {
    id: appMain
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    color: "#FFFF88"

    ListView {
        id: mainListView
        width: parent.width
        height: parent.height
        spacing: 10
        highlight: Rectangle {color: "green";radius: 5; focus: true}
        highlightFollowsCurrentItem: true
        focus: true
        cacheBuffer: 100
        model: listViewModel
        delegate: Rectangle {
            width: parent.width
            height: 35
            color: "transparent"
            Text {
                text: "\t" + id + "\t" + attr
            }

            MouseArea {
                width: parent.width
                height: parent.height
                onClicked: {
                    console.log("click item" + index)
                    mainListView.currentIndex = index
                }
            }
        }
    }

    Item {
        id: scrollBar
        width: 12; height: mainListView.height
        anchors.left: mainListView.left
        opacity: 0.7
        property real position: mainListView.visibleArea.yPosition
        property real pageSize: mainListView.visibleArea.heightRatio/2
        property int orientation: Qt.Vertical
        visible: true

        Rectangle {
            id: background
            anchors.fill: parent
            radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1)
            color: "white"
            opacity: 1.0
        }

        Rectangle {
            x: scrollBar.orientation == Qt.Vertical ? 1 : (scrollBar.position *(scrollBar.width - 2) + 1)
            y: scrollBar.orientation == Qt.Vertical ? (scrollBar.position *(scrollBar.height - 2) + 1) : 1
            width: scrollBar.orientation == Qt.Vertical ? (parent.width - 2) : (scrollBar.pageSize * (scrollBar.width - 2))
            height: scrollBar.orientation == Qt.Vertical ? (scrollBar.pageSize * (scrollBar.height - 2)) : (parent.height - 2)
            radius: scrollBar.orientation == Qt.Vertical ? (width/2 - 1) : (height/2 - 1)
            color: "black"
            opacity: 0.2
        }
    }
}