Как асинхронно обновлять listmodel и listview - PullRequest
0 голосов
/ 26 апреля 2018

Я пишу небольшой код с qml и qt5.

Код читает записи (> 1000 записей) из sqlite db и показывает записи в списке. Сам код работает, как я и предполагал, но я хочу более быстро улучшить интерфейс.

На текущем этапе кнопка запроса не работает в течение длительного времени (около 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 голосов
/ 26 апреля 2018

без тестирования:

Полагаю, ваша проблема заключается в следующих строках:

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

То, что он делает, это добавляет список одного элемента к модели много раз. Каждый вызов вызывает сигнал к представлению, чтобы обновить представление.

Вместо этого вы должны сначала получить полный список всех columnItems и сразу отправить данные в модель.

0 голосов
/ 26 апреля 2018

Вы должны прочитать на QFutureWatcher и посмотреть, может ли это помочь с вашей проблемой. Есть примеры того, как объединить SQListe и Futures.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...