如何在背景中运行顺序启示



我正在设计QT5.7/QML应用程序。主要的想法是,按下按钮将触发shell命令,该命令需要很长时间。该命令的结果应反映在小部件中。
同时,我需要序列化运行,以向用户表明背景中正在发生某些事情。因此,我启动动画,然后调用发送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;
}

这是单读应用程序的问题。您需要在另一个线程中运行shell命令的执行。只需查看使用的Qthread示例即可。主要的事情是,您需要GUI和后端之间基于信号槽的通信(如果您在后端中调用一些"硬"功能)。

与线程一起工作是在许多领域中的态度,例如使用硬盘驱动器(读/写入文件),对服务器或数据库的请求。所有这些都可以同步或异步。对您的基本含义 - 是否冻结主要过程(答案 - 异步方法不会)。

在您的应用中使用Qprocess来调用某些外部命令。Qprocess start()方法将单独执行此命令。这意味着您无需使用QThreads。但是,如果您使用的是waitForFinished(),这会使它变得更加不错。如果您会阅读Qprocess参考,您会发现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 prenher()信号连接到插槽,该插槽将用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]);
        }
    {
}

最新更新