首页 > 解决方案 > 如何在 C++ 代码中的一些“繁重”操作之前使 QML 对象可见

问题描述

我在 QML 中有以下逻辑:

button click handler in QML:

1) rectangle.visible=true

2) call some C++ method

在 C++ 方法中,我调用 QFile::copy,它从 USB 存储复制文件,并将日志打印到上面的矩形(必须已经可见)。但据我了解,QML 仅在执行按钮单击处理程序后才使元素可见,但 QFile::copy 太慢,所以我只有在复制所有文件后才能看到日志(矩形变为可见)。所以我的问题是,如何在调用 QFile::copy 之前使包含日志的矩形可见(真正“可见”)。当然我可以实现异步复制,但我是 Qt 的新手,所以可能有一些解决方案。

谢谢

标签: qtqmlqfile

解决方案


把你的大任务放在一个QThread

任务.hpp

#ifndef THETASK_HPP
#define THETASK_HPP

#include <QThread>

class TheTask: public QThread
{
    Q_OBJECT

    public:
        TheTask(/* Put operation args here, or through some setters. */);

    protected:
        void run() override;

        // Put stuff for storing operation's arguments and results here.
};

#endif  // THETASK_HPP

任务.cpp

#include "thetask.hpp"

TheTask::TheTask() :
    QThread()
    // Init stuff for storing operation's arguments and results.
{}

void TheTask::run() {
    // Put your heavy C++ operation here
}

重的.hpp

#ifndef HEAVY_HPP
#define HEAVY_HPP

#include <QObject>
#include <QList>
class TheTask;

class Heavy: public QObject
{
    Q_OBJECT

    public:
        Heavy();
        virtual ~Heavy();

        /// @brief QML registration
        static void declareQML();

        /// @brief Your heavy operation
        Q_INVOKABLE void doTheBigOperation(/* Operation args */);

    protected:
        /// @brief Storing the running threads for objects lifecycle reasons.
        /// 
        /// The bigOp object would be destroyed at the end of the
        /// Heavy::doTheBigOperation() method. In order to keep it alive,
        /// let's store it in a list.
        QList<TheTask *> bigOps;

    signals:
        /// @brief Emitted when everything is finished.
        void afterBigOp(/* Put operation results here */);

    protected slots:
        /// @brief Treatments to do when the operation is finished.
        void bigOpFinished();
};

#endif  // HEAVY_HPP

重的.cpp

#include "anchor.hpp"
#include <QQmlEngine>
#include "thetask.hpp"

Heavy::Heavy() :
    QObject(),
    bigOps()
{}

Heavy::~Heavy() {
    // Delete threads pointers properly.
    while (!bigOps.isEmpty()) {
        TheTask * thread = bigOps.takeLast();

        // Stopping threads. Be careful on consequences.
        thread->quit();
        thread->wait();

        thread->deleteLater();
    }
}

void Heavy::declareQML() {
    qmlRegisterType<Heavy>("CppGates", 13, 37, "Heavy");
}

void Heavy::doTheBigOperation(/* Operation args */) {
    TheTask * bigOp = new TheTask(/* Operation args */);

    // A thread emits the QThread::finised() signal when its task is finished.
    connect(bigOp, &TheTask::finished,
            this,  &Heavy::bigOpFinished);

    // Keeping the thread alive (cf. bigOps documentation).
    bigOps << bigOp;

    // Start executing the heavy operation.
    bigOp->start();
}

void Heavy::bigOpFinished() {
    // Retrieving the thread, which is the signal sender.
    TheTask * thread = qobject_cast<TheTask *>(sender());

    // The treatment is over: let's broke communication with its thread.
    disconnect(thread, &TheTask::finished,
               this,   &Heavy::bigOpFinished);

    // Extract operation results from the thread.

    // Removing the thread from the running threads list.
    int threadIndex = bigOps.indexOf(thread);
    bigOps.removeAt(threadIndex);

    thread->deleteLater();

    // Telling QML that the heavy operation is over.
    emit afterBigOp(/* Operation results */);
}

RectComp.qml

import QtQuick 2.12
import CppGates 13.37

Item {
    id: qml_comp

    Heavy { id: controller }

    Rectangle {
        id: rectangle

        // ...
    }

    function doItHeavy() {
        rectangle.visible = false
        controller.doTheBigOperation(/* Operation arguments */)
    }

    function afterTheBigOp(/* Operation results */) {
        // Put here things you would like to do after controller.doTheBigOperation()
    }

    Component.onCompleted: {
        // Connecting a callback to the signal emitted after the heavy operation.
        controller.afterBigOp.connect(qml_comp.afterTheBigOp)
    }
}

主文件

#include <QApplication>
#include <QQmlApplicationEngine>
#include "heavy.hpp"

int main(int argc, char ** argv() {
    QApplication app(argc, argv);

    // ...

    Heavy::declareQML();

    // ...

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/qml/main.qml")));
    int res = engine.rootObjects().isEmpty() ? -1 : app.exec();

    // ...

    return res;
}

有关更多信息,请查看QThread参考:https ://doc.qt.io/qt-5/qthread.html


推荐阅读