Listview在重置模型时保留视图

Listview在重置模型时保留视图

本文介绍了Qml Listview在重置模型时保留视图的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个qml listview,它具有c ++的模型.数据从另一个线程生成,并更新为c ++代码模型.之后,我使用 BeginResetModel()来更新qml中的listview.一切正常,除了qml中的视图是从头开始的,但是我希望listview保留当前视图而不更改视图.

I have a qml listview which have a model from c++. The data is generated from another thread and update to model in c++ code. After that, I used BeginResetModel() to update listview in qml. Everything works except the view in qml go the the beginning, but I want the listview keep the current view without changing view.

MWE:

listviewelement.cpp

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.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();
}

main.cpp

#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();
}

main.qml

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
        }
    }
}

推荐答案

从我的观察中,我有一些建议,尽管我没有对其进行测试,所以它可能会起作用,也可能不会起作用.

From what I see, I have several suggestions, though I didn't test it, so it might or might not work.

  • 我看到您仅附加数据,那么为什么可以一一插入行并为此使用 beginInsertRows()和endInsertRows()方法来重置模型?
  • 如果这样做没有帮助,则可以在QML中连接到模型的 modelAboutToBeReset()信号(为此编写一个处理程序 onModelAbouttoBeReset )并保存当前索引在重置之前,然后在重置模型之后,使用处理程序 onModelReset 通过调用 ListView 的"positionViewAtIndex(index,mode)"方法将此列表视图定位在此索引处li>
  • I see that you only append data, so why reset the model when you can insert rows one by one and use beginInsertRows() and endInsertRows() methods for that?
  • If that doesn't help, you might connect in QML to modelAboutToBeReset() signal of the model (write a handler onModelAbouttoBeReset for that) and save your current index before reset, then after you reset the model, use a handler onModelReset to position your listview at this index by calling 'positionViewAtIndex(index, mode)' method of ListView

P.S.您必须在调用 beginResetModel() endResetModel()

P.S. You must change your model between the calls beginResetModel()and endResetModel()

这篇关于Qml Listview在重置模型时保留视图的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-24 01:18