如何在C ++代码中进行一些“繁重”的操作之前使QML对象可见

时间:2019-04-23 18:04:56

标签: qt qml qfile

我在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的新手,所以可能有一些解决方案。

谢谢

2 个答案:

答案 0 :(得分:2)

将大任务放在public static string ToShortString(this TimeSpan Ts) { if(Ts.TotalDays > 1d) return Ts.ToString("d'd:'h'h:'m'm:'s's'"); if(Ts.TotalHours > 1d) return Ts.ToString("h'h:'m'm:'s's'"); if(Ts.TotalMinutes > 1d) return Ts.ToString("m'm:'s's'"); if(Ts.TotalSeconds > 1d) return Ts.ToString("s's'"); if(Ts.TotalMilliseconds > 1d) return Ts.ToString("fffffff'ms'"); return Ts.ToString(); } 中:

thetask.hpp

QThread

thetask.cpp

#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

heavy.hpp

#include "thetask.hpp"

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

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

heavy.cpp

#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

RectComp.qml

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

main.cpp

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; } 的参考文献:https://doc.qt.io/qt-5/qthread.html

答案 1 :(得分:0)

不涉及使用线程的一种可能的“简单”解决方案是延迟使用qml计时器调用c ++方法:

QML中的

按钮单击处理程序:

  1. rectangle.visible = true
  2. 延迟为“ d”的呼叫计时器
  3. 在“ d”之后,计时器将触发并调用您的C ++方法(届时, 矩形应该已经可见了

代码:

Rectangle {
   id: rectangle
}
Button {
   onClicked: {
      rectangle.visible = true
      timer.start()
   }
}
Timer {
   id: timer
   interval: 100
   onTriggered: myCppMethod()
}

请注意,这不会防止您的应用程序在c ++方法执行期间不响应。更好的方法是将cpp方法移动到另一个线程,并使用信号和插槽从主线程调用它。