1

メイン GUI にある進行状況バーの更新をトリガーするループ (いくつかの計算を行う) から信号を発信しました。遅延があり、プログレスバーが100%のままで、マウスがビジーに変わることがあります.数秒後にプログレスバーが非表示になり(遅延が終了したことを示します)、そのループの後に何もないため、何もできませんこの遅れを作ることができると考えています。

  • ループ計算が軽い場合 (つまり、多くの計算を実行する必要がない場合)、そのような遅延は発生しないことに注意してください。

エミットシグナルはロジックレイヤーのクラス内にあります。<QtGui/QApplication>そのクラスに含めることで何かを試しました(これはロジックレイヤーであるため、QtGuiライブラリが必要な理由ですが、私には正しいことではないように思えますが、私は' m は何かをテストするだけです)、次のコードqApp->processEvents();をループ内に配置すると、スムーズに実行され、マウスがビジー状態になることはありませんが、まだ遅延があります (この遅延が発生している間に GUI で反応できる唯一の違いですが、この遅延が終了するまで結果は更新されません)。

でのテストのため、processEvents()スレッドに関連するものだと思っていましたが、もしそうなら、どうすれば遅延動作を修正できますか?

サンプルコード:

ロジック層クラス:

#include <QtGui/QApplication>
...

processMethod(...)
{
    Loop(...)
    {
        qApp->processEvents();
        emit processBarSignle(value);
        ...some calculations...
    }
    emit processBarSignle(100);
}

レイヤーを表示 (MainWindow):

on_btn_nextProcess_clicked()
{
    m_ui->pBar_process->setVisible(true);
    LogicClass->processMethod(...);
    m_ui->pBar_process->setVisible(false);
}

ありがとう

4

2 に答える 2

0

コード サンプルには、実際には 1 つのスレッドしかありません。がon_btn_nextProcess_clicked()呼び出されると、プログレス バーが表示processMethod()され、同じスレッドで実行されます。理想的には、UI とデータ処理ロジックを分離する必要があります。

初期化では、別個の を作成してQThread開始し、logicClassObject->moveToThread([新しいスレッド]) を呼び出して LogicClass オブジェクトをそのスレッドに移動します。次に、processMethod()スロットにしてstartProcessing()、MainWindow で信号を作成し、2 つを接続します。最後に、processingDone()スロットインMainWindowfinishedProcessing()スロットインを作成しLogicClassて接続します。これがすべて設定されたら、コードを次のように変更できます。

void LogicClass::processMethod(...)
{
    Loop(...)
    {
        emit processBarSignal(value);
        ...some calculations...
    }
    emit processingDone();
}

void MainWindow::on_btn_nextProcess_clicked()
{
    m_ui->pBar_process->setVisible(true);
    emit startProcessing(...);
}

void MainWindow::finishedProcessing()
{
    m_ui->pBar_process->setVisible(false);
}

2 つの別々のスレッドからシグナルとスロットを接続すると、マルチスレッドが自動的に処理されます。1 つのスレッドでシグナルを発行すると、別のスレッドでイベントがキューに入れられ、2 番目のスレッドが制御を取り戻したときにのみスロットが呼び出されます。

この場合、UI スレッドは処理スレッドでイベントをスケジュールして処理を開始します。処理スレッドは、progressBar 値の更新を継続的にスケジュールし、最後に、完了時に進行状況バーをオフにするイベントをスケジュールします。2 つのスレッドは OS スレッド スケジューラに従って実行され、処理によって UI がブロックされることはありません。

于 2013-01-18T13:50:29.400 に答える
0

次のことを試してください。

#include <QtCore/QCoreApplication>
...

processMethod(...)
{
    Loop(...)
    {
        emit processBarSignle(value);
        QCoreApplication::processEvents();
        ...some calculations...
    }
    emit processBarSignle(100);
    QCoreApplication::processEvents();
}

processEvents()QCoreApplicationの静的メソッドであり、ライブラリQCoreApplicationの一部だけを含めるだけで十分です。QtCore

さらにprocessEvents()、進行状況バーが更新される前ではなく、更新された後に追加する必要があります。

processEvents()Qt のイベント キュー内のすべてのイベントが処理されるまで返されないことに注意してください。ボタンなどがある場合はCancel、 を呼び出すたびに、ユーザーが実際に操作をキャンセルしたかどうかを確認する必要がありますprocessEvents()
を使用して、マウスクリック/キープレスなどのユーザー固有のイベントを除外できます

QCoreApplication::processEvents( QEventLoop::ExcludeUserInputEvents )

ただし、ループがアクティブな間は何もクリックできません (キャンセル ボタンなど)。

さらに注意してください: 「processBarSingle」と呼ぶ必要があります;-)


スレッドなどの説明:

ループ全体とマウスのクリックなどは、1 つのスレッドでのみ実行されます。を呼び出すemit()と、slotそれに接続されているsignalが即座に実行されます (スロットが実際に別のスレッドにない場合)。その間、ループは続きません!

スロットが終了すると、ループが続行されます。私の例では、この手段processEvents()が呼び出されます。これで、スロットがプログレス バーを更新したり、再描画を引き起こす何かを行ったりした場合、イベント キューに再描画イベントが発生し、この再描画が行われるようになります。
スロットを呼び出す前に実行processEvents()すると、この時点で処理できる再描画イベントはありません。

繰り返しますが、ループは が完全に終了するまで続きませんprocessEvents()。保留中のすべてのイベントが処理されると、ループは計算を続行します。

于 2013-01-18T11:58:33.287 に答える