如何使用PBS_MARQUEE样式使ProgressBar工作?

时间:2017-09-28 07:46:53

标签: c++ winapi controls progress-bar

我知道如何使用PBS_MARQUEE样式创建一个有效的ProgressBar,但是在我希望运行选框动画的情况下,只要运行一些long_operation(),我就无法实现它,而无需调用{{1} } {从持续SendMessage(hPB, PBM_STEPIT, 0, 0);以推进动画。

这是我失败的尝试之一:

long_operation()

上面的代码我得到的是一个没有任何动画的选框进度条,同时继续发出哔哔声,然后是一个正常的动画选框,当它停止时。

据我所知,由于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(); } 阻塞了线程,因此消息队列也被阻止,并且ProgressBar控件不会发送默认的30ms更新消息。

我觉得必须有一种直观的方法来做到这一点,但我无法弄明白。

这是怎么回事?

1 个答案:

答案 0 :(得分:0)

如果您希望保留一个线程,则需要定期提取消息,以便在未覆盖时移动或刷新窗口。

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

这可以通过添加Abort按钮,在ProgressDlgProc中处理WM_COMMAND,设置一些标志(Dll_globals :: g_Abort?)并提前离开long_operation来增强。

进行多线程,你必须建立开始工作的协议(这取决于你选择的API)和信令完成(这可以通过PostMessage使用自定义消息甚至具有足够控制ID的WM_COMMAND来完成)。即使在这种情况下,当用户在完成早期调用之前再次启动相同操作时,要注意潜在的问题。