我正在设计Qt5.7 / QML应用程序。主要思想是按下按钮会触发shell命令,这需要很长时间。该命令的结果应反映在小部件中 与此同时,我需要运行SequentialAnimation,以向用户显示后台正在发生的事情。所以我启动动画,然后调用发送shell命令的进程 但是动画似乎被冻结为整个GUI,直到shell命令返回 有什么建议吗? QML代码:
CircularGauge {
id: speedometer_wr
x: 199
y: 158
value: valueSource.bps
maximumValue: 400
width: height
height: container.height * 0.5
stepSize: 0
anchors {
verticalCenter: parent.verticalCenter
verticalCenterOffset: 46
}
style: DashboardGaugeStyle {}
NumberAnimation {
id: animation_wr
running: false
target: speedometer_wr
property: "value"
easing.type: Easing.InOutSine
from: 0
to: 300
duration: 15000
}
}
Button {
id: button_benchmark
x: 168
y: 26
width: 114
height: 47
text: qsTr("Benchmark")
tooltip: "Execute the performance test"
checkable: true
function handle_becnhmark() {
speedometer_wr.value = 0;
// Uncheck the button
button_benchmark.checked = false;
// Start the animation
animation_wr.start();
// Run the benchmark
var res = backend.run_benchmark();
// Stop the animation
animation_wr.stop();
speedometer_wr.value = parseFloat(res.split(",")[0]);
}
onClicked: {handle_becnhmark()}
}
Cpp代码:
#include <QProcess>
#include <QtDebug>
#include "backend.h"
#include <QRegExp>
BackEnd::BackEnd(QObject *parent) : QObject(parent)
{
}
QString BackEnd::run_benchmark() {
qDebug() << "in run_benchmark";
QProcess proc;
// Execute shell command
proc.start(<LONG_SHELL_COMMAND>);
if (!proc.waitForStarted())
return "";
if (!proc.waitForFinished())
return "";
// Get the results, parse and return values
QString result(proc.readAll());
return result;
}
答案 0 :(得分:0)
是单线程应用程序的问题。您需要在另一个线程中运行shell命令的执行。只需查看QThread使用示例。主要的是你需要在GUI和后端之间进行基于信号槽的通信(如果你在后端调用一些&#34;硬&#34;函数)。
在许多方面使用线程,例如使用硬盘驱动器(读取/写入文件),请求服务器或数据库。所有这些都可以同步完成或asynchrony。你的基本意义 - 它是否会冻结主要过程(答案 - 异步方法不会)。
在您的应用中使用QProcess调用一些外部命令。 QProcess start()方法将自动异步执行此命令。这意味着您不需要使用QThreads。但如果你使用的是waitForFinished()
,那就明白了。如果您阅读QProcess reference,您会看到waitForStarted()
和waitForFinished()
方法是同步的。这意味着他们确实会冻结主进程和GUI。
所以你需要的是
在类标题中声明指向QProcess的指针(最好使用QSharedPointer<QProcess>
)
class BackEnd : public QObject {
...
private slots:
void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus);
signals:
void executionEnds(const QString &res);
private:
QProcess* proc;
}
在源代码中,您需要初始化proc
并将QProcess finished()信号连接到插槽,该插槽将proc
命令执行的输出与BackEnd
中的另一个信号一起推送。
BackEnd::BackEnd(QObject *parent) : QObject(parent) {
proc = new QProcess();
connect(proc, &QProcess::finish, this, &BackEnd::handleProcFinished);
}
void handleProcFinished(int exitCode, QProcess::ExitStatus exitStatus) {
//check code
...
QString result("");
if (all is fine) {
result = proc->readAll();
} else {
//debug or something else
}
emit executionEnds(result);
}
在QML方面,它将是这样的:
Button {
onClicked: {
speedometer_wr.value = 0;
// Uncheck the button
button_benchmark.checked = false;
// Start the animation
animation_wr.start();
// Run the benchmark
var res = backend.run_benchmark();
}
}
Connections {
target: backend //[name of some contextProperty which will be emiting the signals]
onExecutionEnds: {
animation_wr.stop();
if (res != "") {
speedometer_wr.value = parseFloat(res.split(",")[0]);
}
{
}