1

タイトルはかなり明確です。数ミリ秒間スリープしてから、GUI を停止せずに関数を呼び出す方法があるかどうかを知る必要があるだけです。私が今行っている方法は追加するだけSleep(3000);で、これにより、スリープ時間が完了するまで GUI がフリーズします。

スレッドを追加Sleep()してから関数を呼び出そうとしましたが、関数が GUI 要素を変更し、スレッドでは GUI 要素 (ラベル、ボタンなど) にアクセスできないため、機能しません。 .

では、GUI を停止せずに、コードが続行するまで数秒待機させるにはどうすればよいでしょうか?

ところで、Sleep は a の内部にありますbackgroundWorker_RunWorkerCompleted(これは、backgroundworker が完了した後の BackgroundWorker のコールバックです)。

void backgroundWorker_RunWorkerCompleted(Object^ /*sender*/, RunWorkerCompletedEventArgs^ e){

     printf("Done, Waiting 3 seconds to do something that has to be 3 seconds after.");
     Sleep(3000); //at this point the UI freezes
     this->CallFunction();     

}

これを行う方法のヒント/提案はありますか?

4

4 に答える 4

1

GUI については言及していますが、特定の UI フレームワークについては言及していません。当面は WinAPI を想定しますが、概念的には、他のフレームワークの大多数がこれから説明する内容を備えています。

Win32 では、タイマーを使用して目的を達成できます。WM_CREATEまたはなどで、 SetTimerWM_INITDIALOGでタイマーを設定します。次に、システムは指定したタイムアウト値を取得し、その値が経過するたびに、ウィンドウにWM_TIMERメッセージで通知します。すぐに戻るので、UI スレッドをブロックしません。SetTimer

これを行う別の方法は、最初に新しいスレッドを開始することです。この新しいスレッドはスリープを実行し、3 秒ごとに実行する必要があるすべての作業を実行します。別のスレッドで実行されるため、UI がロックアップすることはありません。からは常に迅速に/すぐに戻る必要がありWndProcます。多くの作業を行う必要がある場合は、その作業を別のスレッドに委任して、重い作業を行う必要があります。

于 2012-04-10T15:37:06.293 に答える
0

クイックフィックス:Sleep呼び出しをイベントハンドラーBackgroundWorkerではなくタスク内に配置します。RunWorkerCompletedイベントハンドラーはGUIスレッドで実行されます。

より良い修正:マイクが提案したようなタイマーについて学びましょう。WinFormsは、選択した遅延の後にイベントを発生させるタイマーを提供します。スリープして終了するためだけにバックグラウンドタスクを開始するのは、ひどい無駄です。

于 2012-04-10T16:18:23.783 に答える
0

バックグラウンド スレッドに、メイン スレッドのミューテックス変数にフラグを設定させます。これにより、バックグラウンド スレッド (メイン スレッド) に、実行中の処理を続行しても安全であることを伝えます。これはストップ ライトのようなものです。すべてのコーナー (両側) には、相互に関連するライトがあります。

メイン スレッドは一時停止しませんが、(gui などの) メッセージを処理する while ループを使用できますが、ミューテックス変数が設定されるまでループを中断しません。これはバックグラウンド スレッドで発生します。

開始するための参考資料を次に示します。

編集 -- リクエストごと:

グローバルに、ミューテックス ハンドルと変数を定義します。

HANDLE sharedMemoryMutex = CreateMutex(NULL, FALSE, "My mutex =)!");
BOOL good2Go = false;

次に、バックグラウンド スレッドでは、次のようになります。

void wait() {
    // First, we sleep...
    sleep(3000);

    // Now, we request a lock on the good2Go variable, so that when we write to
    // it, no other thread is:
    DWORD dwWaitResult = WaitForSingleObject(sharedMemoryMutex, INFINITE);
    if (dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED) {
    if (dwWaitResult == WAIT_ABANDONED) {
            // Shared memory is maybe in inconsistent state because other program
            // crashed while holding the mutex. Check the memory for consistency
            ...
    }

    // Access your shared memory
    good2Go = true;

    // Release the lock so that the main thread can read the variable again..
    ReleaseMutex(sharedMemoryMutex);
}

次に、メインスレッドでは、次のようになります。

// Create your background wait thread:
// .....

while(true) {

    // Handle messages so that your program doesn't appear frozen.
    // You will have to do your research on this one =)
    YourMessageHandler();

    // Request a lock on the good2Go variable, so we can read it w/o corrupting it
    DWORD dwWaitResult = WaitForSingleObject(sharedMemoryMutex, INFINITE);
    if (dwWaitResult == WAIT_OBJECT_0 || dwWaitResult == WAIT_ABANDONED) {
    if (dwWaitResult == WAIT_ABANDONED) {
            // Shared memory is maybe in inconsistent state because other program
            // crashed while holding the mutex. Check the memory for consistency
            ...
    }

    // Exit the loop
    if( good2Go ) { ReleaseMutex(sharedMemoryMutex); break; }
    ReleaseMutex(sharedMemoryMutex);
}

// Continue your code after the 3 pause....

まだわからない場合は、メッセージの処理方法を理解する必要があります。また、ミューテックスの実装は異なる場合がありますが、VC を使用しているとのことでしたので、上記の win32 実装で問題ありません。そして、私はあなたが一般的な概念を理解していると思います

于 2012-04-10T14:10:18.477 に答える
0

VC++/CLI を使用しているため、C# のいとこです。別のスレッドから GUI を更新する方法については、こちらを参照してください。

C#で別のスレッドからGUIを更新するには?

于 2012-04-10T16:14:12.783 に答える