2017-09-28 10 views
0

私はPBS_MARQUEEスタイルでの作業プログレスバーを作成する方法を知っているが、私はアニメーションを進めるためにlong_operation()から連続SendMessage(hPB, PBM_STEPIT, 0, 0);を呼び出さず、トラブル私がいる限り、いくつかのlong_operation()実行などマーキーアニメーションをしたいような状況で、それを実装したのです。それが停止したときにビープ音が継続している間、私は上記のコードで何を得るPBS_MARQUEEスタイルのProgressBarを作成するには?

INT_PTR CALLBACK ProgressDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { 
    switch(message) { 
     case WM_INITDIALOG: 
     { 
      HWND hProgressBar = GetDlgItem(hWnd, IDC_PROGRESS1);     
      LONG_PTR style_flags = GetWindowLongPtr(hProgressBar, GWL_STYLE); 
      SetWindowLongPtr(hProgressBar, GWL_STYLE, style_flags | PBS_MARQUEE); 

      SendMessage(hProgressBar, (UINT)PBM_SETMARQUEE, (WPARAM)1, (LPARAM)NULL); 

      break; 
     } 
    } 

    return FALSE; 
} 

void long_operation() { 
    for(int i = 0; i < 9; ++i) { 
     for(int j = 0; j < 99999999; ++j) 
     ; 
     Beep(5000, 100); 
    } 
} 

void do_operation() { 
    HWND hDlg = CreateDialog(Dll_globals::g_hInst, 
          MAKEINTRESOURCE(IDD_DIALOG4), // assume this contains a ProgressBar ctl 
          Dll_globals::g_hWndMain, ProgressDlgProc); 
    if(hDlg) { 
     ShowWindow(hDlg, SW_SHOW); 
     UpdateWindow(hDlg); 
    } 

    long_operation(); 
} 

は、任意のアニメーションなしマーキープログレスバーで、その後、通常のアニメーションマーキー:ここ

は私の失敗の一つです。

私が理解する限り、long_operation()はスレッドをブロックするので、メッセージキューもブロックされ、デフォルトの30msの更新メッセージはProgressBarコントロールに送受信されません。

これを行うには直感的な方法が必要だと感じますが、わかりません。

これについてはどうすればよいですか?

+0

std :: threadが直感的であると非難されたことがあまりにも確実ではない。しかし、これは、UIスレッドがバーを更新できるようにするために必要なことです。プログレスバーの代わりに砂時計のカーソルがかなり直感的です。 –

+2

'long_operation'をワーカースレッドにオフロードします。これは多くの方法で行うことができる。 'std :: thread'、' std :: async'、またはWindowsのネイティブスレッドの実装( 'CreateThread' /' _beginthreadex')を使用します。特に、 'long_operation'から' SendMessage'を呼び出すことは、部分的な解決策を実装するだけです。それでも、他のメッセージのディスパッチを防ぎ、ユーザーが対話しようとしているときなどにダイアログがハングアップしているように見せかけます。 – IInspectable

+0

何が起こっているのは、あなたがUIを応答しないようにするUIスレッドで作業しているということです。バックグラウンドスレッドで作業を行うことでその問題を解決してください。 –

答えて

0

1つのスレッドに留まることを希望する場合は、メッセージが定期的にポンピングされ、ウィンドウが開かれた場合にウィンドウを移動またはリフレッシュする必要があります。

// Process all queued messages. Handle keyboard dialog nawigation 
// for dialog_hwnd. For more then one modeless dialog modify code by 
// calling IsDialogMessage for each dialog. 
void PumpMesages(HWND dialog_hwnd) { 
    MSG msg; 
    while (PeekMessage(&msg, 0, 0, 0, PM_REMOVE) != 0) { 
     // Handling modeless dialog nawigation. 
     if (dialog_hwnd && IsDialogMessage(dialog_hwnd)) 
      continue; 

     TranslateMessage(&msg); 
     DispatchMessage(&msg); 
    } 
} 

void long_operation(HWND dialog_hwnd, HWND progress_hwnd) { 
    for(int i = 0; i < 9; ++i) { 
     for(int j = 0; j < 99999999; ++j) 
     ; 

     // I'm not shure if this is needed. 
     // I have always used propper progress bar (PBM_SETPOS). 
     SendMessage(progress_hwnd, PBM_STEPIT, 0, 0); 
     // Periodically process messages. 
     PumpMessages(dialog_hwnd); 

     Beep(5000, 100); 
    } 
} 

void do_operation() { 
    HWND hDlg = CreateDialog(Dll_globals::g_hInst, 
          MAKEINTRESOURCE(IDD_DIALOG4), // assume this contains a ProgressBar ctl 
          Dll_globals::g_hWndMain, ProgressDlgProc); 
    if(hDlg==0) 
     return; 

    ShowWindow(hDlg, SW_SHOW); 

    // Disable input processing in main window if there is possibility 
    // of recursion. For example, user select Open file, we begin 
    // loading and inside PumpMessages, user can again select Open 
    // file so we will end with two progress dialogs and nested 
    // message loops. 
    EnableWindow(Dll_globals::g_hWndMain,FALSE); 

     long_operation(hDlg, GetDlgItem(hDlg, progress_bar_id_here)); 

    // Remember to enable input processing in main window. 
    EnableWindow(Dll_globals::g_hWndMain,TRUE); 
} 

これは(?Dll_globals :: g_Abort)、ボタンを中止追加ProgressDlgProcでWM_COMMANDを処理し、いくつかのフラグを設定することにより強化され、早期long_operationを残すことができます。

マルチスレッドに移行するには、作業を開始するためのプロトコル(これは選択するAPIによって異なります)とシグナリングの完了(これはPostMessageによってカスタムメッセージまたは適切な制御IDを持つWM_COMMANDでも可能です)を確立する必要があります。このシナリオでも、ユーザーが以前の呼び出しが完了する前に同じ操作を再度開始すると、潜在的な問題に注意してください。

+0

この提案されたソリューションは、ダイアログ内のキーボードナビゲーションを中断します。キーボードナビゲーションは、[IsDialogMessage](https://msdn.microsoft.com/en-us/library/windows/desktop/ms645498.aspx)API呼び出しによって実装されます。 – IInspectable

+0

はい、あなたは正しいです、私たちはモードダイアログを使用していますので、カーボードの操作を処理するにはIsDialogMessageが必要です。それを忘れてしまった。更新されたコード。 –

+0

このソリューションの問題点は、ユーザーがUIとやりとりするときに遅れが生じることです。 'long_operation'は十分短いインターバル内で' PumpMessages() 'を呼び出すことができないかもしれません。そうであっても、内部ループから 'PumpMessages()'が呼び出されると、パフォーマンスが低下する可能性があります。 – zett42

関連する問題