我在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的新手,所以可能有一些解决方案。
谢谢
答案 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中的按钮单击处理程序:
代码:
Rectangle {
id: rectangle
}
Button {
onClicked: {
rectangle.visible = true
timer.start()
}
}
Timer {
id: timer
interval: 100
onTriggered: myCppMethod()
}
请注意,这不会防止您的应用程序在c ++方法执行期间不响应。更好的方法是将cpp方法移动到另一个线程,并使用信号和插槽从主线程调用它。