我知道如何使用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更新消息。
我觉得必须有一种直观的方法来做到这一点,但我无法弄明白。
这是怎么回事?
答案 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来完成)。即使在这种情况下,当用户在完成早期调用之前再次启动相同操作时,要注意潜在的问题。