如何异步更新listmodel和listview

时间:2018-04-26 10:30:46

标签: c++ qt qml

我正在用qml和qt5编写一个小代码。

代码正在从sqlite db中读取记录(> 1000条记录)并显示 列表视图上的记录。代码本身正如我所预期的那样工作,但我想要更加响应地改进UI。

在当前阶段,当我按下获取记录的按钮时,查询按钮很长时间(大约4分钟)已经死亡。 所以我想让代码运行另一个从sqlite db收集记录并更新listview的线程。 同时,我想在收集记录时显示busyindicator。

我研究了关于线程的qml和qt5,但很难理解如何应用于listmodel。目前,我不是根据qml提示考虑工人。

如果有人能用我的代码向我展示一些实现,我将不胜感激:

的main.cpp

#include <QApplication>
#include <QQmlApplicationEngine>
#include <QQuickView>
#include <QDir>
#include <QQmlContext>
#include <QStandardItemModel>

#include "DBObject.h"
#include "EnvironmentModel.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    QApplication app(argc, argv);
    QQmlApplicationEngine engine;
    QQmlContext *ctxt = engine.rootContext();

    EnvironmentModel* model = new EnvironmentModel;
    ctxt->setContextProperty("environmentModel", model);

    DBObject* DB = new DBObject;
    DB->setEnvironmentModel(model);

    ctxt->setContextProperty("DB", DB);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml

import QtQuick 2.10
import QtQuick.Controls 2.3
import "listView"

ApplicationWindow {
    id: mainWindow
    visible: true
    width: 740
    height: 640

    title: qsTr("DB query")

    Page1 {
        id: page1
    }
}

page1.qml

import QtQuick 2.10
import QtQuick.Controls 2.3
import QtQuick.Dialogs 1.3
import "listView"

Item {
    id: page1
    anchors.fill: parent
    readonly property int margin: 10

        Button {
            text: "Query"

            onClicked: {
                DB.registerCoordinate(78, 124);
                DB.setYearRange(1979, 1980);
                popup.open()
            }
        }
    }

    Popup {
            id: popup
            x: 1
            y: 1
            width: parent.width
            height: parent.height
            modal: true
            focus: true
            visible: false

            onVisibleChanged:  {
                DB.query()
            }

            Rectangle {
                id: titleBar
                width: parent.width
                height: 20
                color: "#bebebe"
                Row {
                    spacing: 10
                    Text { width: 100; text: "Index"; horizontalAlignment: Text.AlignHCenter }
                    Text { width: 100; text: "Date"; horizontalAlignment: Text.AlignHCenter }
                    Text { width: 100; text: "Time"; horizontalAlignment: Text.AlignHCenter }
                    Text { width: 100; text: "Hs"; horizontalAlignment: Text.AlignHCenter }
                    Text { width: 100; text: "Tp"; horizontalAlignment: Text.AlignHCenter }
                    Text { width: 100; text: "Dp"; horizontalAlignment: Text.AlignHCenter }
                    Text { width: 100; text: "Vw"; horizontalAlignment: Text.AlignHCenter }
                    Text { width: 100; text: "Dw"; horizontalAlignment: Text.AlignHCenter }
                }
            }

            Page2 {
                id: resultWindow
                anchors.left: parent.left
                anchors.leftMargin: 10
                anchors.right: parent.right
                anchors.rightMargin: 10
                anchors.top: titleBar.bottom
                anchors.topMargin: 10
                anchors.bottom:bottomBar.top
                anchors.bottomMargin: 10
            }

            closePolicy: Popup.CloseOnEscape

        }
}

page2.qml

import QtQuick 2.10
import QtQuick.Controls 2.3
import "listView"

Item {

    id: page2
    EnvironmentList {
        height:200
        width: parent.width
    }
}

EnvironmentList.qml

import QtQuick 2.10
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.0
import QtLocation 5.6
import QtPositioning 5.6


Rectangle {
    id: container
    anchors.fill: parent
    Component {
        id: environmentDelegate
        Row {
            spacing: 10
            Text { width: 100; text: index+1; horizontalAlignment: Text.AlignHCenter}
            Text { width: 100; text: date; horizontalAlignment: Text.AlignHCenter}
            Text { width: 100; text: time; horizontalAlignment: Text.AlignHCenter}
            Text { width: 100; text: hs.toFixed(2); horizontalAlignment: Text.AlignHCenter}
            Text { width: 100; text: tp.toFixed(2); horizontalAlignment: Text.AlignHCenter}
            Text { width: 100; text: dp.toFixed(2); horizontalAlignment: Text.AlignHCenter}
            Text { width: 100; text: vw.toFixed(2); horizontalAlignment: Text.AlignHCenter}
            Text { width: 100; text: dw.toFixed(2); horizontalAlignment: Text.AlignHCenter}
        }
    }

    ListView {
        id: environmentList
        anchors.fill: parent
        model: environmentModel
        delegate: environmentDelegate
        flickableDirection: Flickable.VerticalFlick
        boundsBehavior: Flickable.StopAtBounds
        ScrollBar.vertical: ScrollBar {}
    }
}

EnvironmentModel.h

#ifndef ENVIRONMENTMODEL_H
#define ENVIRONMENTMODEL_H

#include <QQuickView>
#include <QQmlContext>
#include <QStandardItemModel>

class EnvironmentModel : public QStandardItemModel
{
    Q_OBJECT
public:
    EnvironmentModel() : QStandardItemModel()
    {
        QHash<int, QByteArray> roleNames;
        roleNames[Qt::UserRole + 1] =  "date";
        roleNames[Qt::UserRole + 2] =  "time";
        roleNames[Qt::UserRole + 3] =  "lat";
        roleNames[Qt::UserRole + 4] =  "lon";
        roleNames[Qt::UserRole + 5] =  "hs";
        roleNames[Qt::UserRole + 6] = "tp";
        roleNames[Qt::UserRole + 7] = "dp";
        roleNames[Qt::UserRole + 8] =  "vw";
        roleNames[Qt::UserRole + 9] = "dw";
        this->setItemRoleNames(roleNames);
    }

    Q_INVOKABLE void writeToCSV(const QString& path);
};


#endif /* ENVIRONMENTMODEL_H */

DBObject.h

#ifndef DBOBJECT_H
#define DBOBJECT_H

#include <QObject>
#include <vector>
#include "DB.h"
#include "EnvironmentModel.h"

class DBObject : public QObject
{
    Q_OBJECT
public:
    explicit DBObject(QObject* parent = 0);

public:
    void setEnvironmentModel(EnvironmentModel* model);

    Q_INVOKABLE void registerCoordinate(float lat, float lon);
    Q_INVOKABLE void setYearRange(unsigned yearStart, unsigned yearEnd);
    Q_INVOKABLE void query();

private:
    DB db_;
    EnvironmentModel* model_;
    unsigned yearStart_;
    unsigned yearEnd_;
    std::vector<float> lats_;
    std::vector<float> lons_;
};

#endif /* DBOBJECT_H */

DBObject.cpp

#include <QDebug>
#include <QDir>
#include "DBObject.h"

DBObject::DBObject(QObject* parent)
    : QObject(parent)
{}

void DBObject::setEnvironmentModel(EnvironmentModel* model) {
    model_ = model;
}

void DBObject::registerCoordinate(float lat, float lon) {
   lons_.push_back(lon);
   lats_.push_back(lat);
}

void DBObject::setYearRange(unsigned yearStart, unsigned yearEnd) {
    yearStart_ = yearStart;
    yearEnd_ = yearEnd;
}

void DBObject::query()
{
    for (auto i=0U; i<lats_.size(); ++i)
    {
        std::list<DB::Record> records = db_.query(yearStart_, yearEnd_, lons_[i], lats_[i]);
        for(auto iter=records.begin(); iter!=records.end(); ++iter)
        {
            QList<QStandardItem*> columnItems;
            QStandardItem *item = new QStandardItem();
            item->setData(iter->date_, Qt::UserRole + 1);
            item->setData(iter->time_, Qt::UserRole + 2);
            item->setData(iter->lat_, Qt::UserRole + 3);
            item->setData(iter->lon_, Qt::UserRole + 4);
            item->setData(iter->hs_, Qt::UserRole + 5);
            item->setData(iter->tp_, Qt::UserRole + 6);
            item->setData(iter->dp_, Qt::UserRole + 7);
            item->setData(iter->vw_, Qt::UserRole + 8);
            item->setData(iter->dw_, Qt::UserRole + 9);
            columnItems << item;
            model_->appendRow( columnItems );
        }
    }
}

2 个答案:

答案 0 :(得分:1)

没有测试:

我想,你的问题在于这些方面:

for (auto i=0U; i<lats_.size(); ++i)
{
    std::list<DB::Record> records = db_.query(yearStart_, yearEnd_, lons_[i], lats_[i]);
    for(auto iter=records.begin(); iter!=records.end(); ++iter)
    {
        QList<QStandardItem*> columnItems;
        QStandardItem *item = new QStandardItem();
        item->setData(iter->date_, Qt::UserRole + 1);
        item->setData(iter->time_, Qt::UserRole + 2);
        item->setData(iter->lat_, Qt::UserRole + 3);
        item->setData(iter->lon_, Qt::UserRole + 4);
        item->setData(iter->hs_, Qt::UserRole + 5);
        item->setData(iter->tp_, Qt::UserRole + 6);
        item->setData(iter->dp_, Qt::UserRole + 7);
        item->setData(iter->vw_, Qt::UserRole + 8);
        item->setData(iter->dw_, Qt::UserRole + 9);
        columnItems << item;
        model_->appendRow( columnItems );
    }
}

它的作用是,它多次将单个项目的列表附加到模型中。 每次调用都会触发一个信号到视图,以刷新视图。

相反,您应首先获取所有columnItem的完整列表,然后立即将数据推送到模型。

答案 1 :(得分:0)

您应该阅读QFutureWatcher并查看是否可以解决您的问题。有关如何组合SQListe和Futures的示例。