2017-12-25 31 views
0

私はQt5.7/QMLアプリケーションを設計しています。主な考え方は、ボタンを押すとシェルコマンドが起動し、時間がかかります。このコマンドの結果はウィジェットに反映する必要があります。
その間、何かがバックグラウンドで起こっていることをユーザーに示すために、実行するにはSequentialAnimationが必要です。だから私はアニメーションを開始し、シェルコマンドを送信するプロセスを呼び出します。
しかし、シェルコマンドが戻るまでアニメーションはGUI全体としてフリーズしているようです。
提案がありますか?
QMLコード:SequentialAnimationをバックグラウンドで実行するには?

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

[MCVE]を提供してください。シェルコマンド実行中にイベントを処理するのを忘れているかのように聞こえます。 –

答えて

0

それはsinglethreadアプリケーションの問題です。別のスレッドでシェルコマンドの実行を実行する必要があります。ちょうどQThreadの使用例を見てください。主なものは、GUIとバックエンド(バックエンドでいくつかの「ハード」機能を呼び出す場合)の間でシグナルスロットベースの通信が必要なことです。

スレッドの操作は、ハードドライブ(ファイルへの読み書き)、サーバーまたはデータベースへの要求など、多くの領域で重要です。これはすべて同期的に行うことも、asynchronyで行うこともできます。あなたのための基本的な意味 - それがメインプロセスをフリーズするかどうか(答え - 非同期メソッドはそうではありません)。

アプリでは、QProcessを使用して外部コマンドを呼び出しています。 QProcess start()メソッドは、このコマンドを非同期的に単独で実行します。つまり、QThreadを使用する必要はありません。しかし、あなたがwaitForFinished()を使用している場合は意味があります。 QProcess referenceを読むと、waitForStarted()waitForFinished()のメソッドが同期していることがわかります。つまり、彼らはメインプロセスとGUIを実際にフリーズします。

それで、あなたが必要なもの、あなたがprocを初期化し、QProcessを接続する必要があるソースでは、クラスのヘッダ内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; 
    } 
    
  • あるfinished()スロットへの信号は、procコマンドによって実行された出力をBackEndの別の信号でプッシュします。それはこのようなものになりますQML側で

    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); 
    } 
    

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]); 
     } 
    { 
} 
+0

私はQt/QMLの新しいコーナーです。スレッドクラスのコードとその使い方を追加してください。 –

関連する問題