[英]Win32 API: How to avoid flickering of basic window controls?
我通过根据滚动条上的当前nPos值使WM_PAINT内部的所有内容无效并重新绘制它们来滚动父窗口。 我想滚动而不闪烁,所以我处理WM_ERASEBKGND以避免重绘背景。 我还对TextOut调用和显示的某些位图进行了简单的双重缓冲。 除了我的孩子可以控制之外,它的效果很好。 它们严重闪烁,特别是当nPos == 0且应用程序处理SB_LINEUP或nPos == nMax且应用程序处理SB_LINEDOWN或拖放滚动条时。 我用MoveWindow()移动它们。 我也尝试过DeferWindowPos()。 我在Google上搜索了用于闪烁的解决方案,但它不起作用或我没有正确使用它。 如何消除子控件的闪烁?
PS:当我在主窗口中使用WS_CLIPCHILDREN样式时,控件不会闪烁,但在滚动窗口的某些部分时会弄乱,特别是我的静态控件,通过处理WM_DRAWITEM在其中绘制某些内容。
编辑:(简化的代码)我在WM_PAINT内部这样的双缓冲区:
case WM_PAINT: {
hDC = BeginPaint( hwnd, &PS );
hDCMem = CreateCompatibleDC( hDC );
hBMMem = CreateCompatibleBitmap( hDC, wnd_x, wnd_y );
SelectObject( hDCMem, hBMMem );
Font = CreateFont( 130, 50, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_MODERN, "Arial" );
SelectObject( hDCMem, Font );
SetTextColor( hDCMem, RGB( 30, 144, 255 ) );
SetBkColor( hDCMem, RGB( 192, 192, 192 ) );
TextOut( hDCMem, 650, 69 - scr_pos, "ABC", 3 );
MoveWindow( GetDlgItem( hwnd, ID_BUTT_START ), 720, 500 - scr_pos, 160, 150, TRUE );
BitBlt( hDC, 0, 0, wnd_x, wnd_y, hDCMem, 0, 0, SRCCOPY );
DeleteObject( hBMMem );
DeleteDC( hDCMem );
EndPaint( hwnd, &PS );
}
scr_pos是从滚动条获取的当前nPos值。
case WM_ERASEBKGND:
return 1;
break;
case WM_VSCROLL: {
SCROLLINFO sinfo;
ZeroMemory( &sinfo, sizeof( SCROLLINFO ) );
sinfo.cbSize = sizeof( SCROLLINFO );
sinfo.fMask = SIF_POS | SIF_PAGE | SIF_TRACKPOS;
GetScrollInfo( hwnd, SB_VERT, &sinfo );
scr_pos = sinfo.nPos;
switch( LOWORD( wParam ) ) {
case SB_TOP:
scr_pos = 0;
break;
case SB_BOTTOM:
scr_pos = 4000;
break;
case SB_LINEUP: {
scr_pos -= 200;
if ( scr_pos < 0 ) {
scr_pos = 0;
}
}
break;
case SB_LINEDOWN: {
scr_pos += 200;
if ( scr_pos > 4000 ) {
scr_pos = 4000;
}
}
break;
case SB_PAGEUP: {
scr_pos -= si.nPage;
if( scr_pos < 0 ) {
scr_pos = 0;
}
}
break;
case SB_PAGEDOWN: {
scr_pos += si.nPage;
if( scr_pos > 4000 ) {
scr_pos = 4000;
}
}
break;
case SB_THUMBPOSITION:
scr_pos = HIWORD(wParam);
break;
case SB_THUMBTRACK:
scr_pos = HIWORD(wParam);
break;
}
RedrawWindow( hwnd, NULL, NULL, RDW_INVALIDATE | RDW_INTERNALPAINT );
// InvalidateRect ( hwnd, NULL, true );
// UpdateWindow( hwnd );
ZeroMemory( & sinfo, sizeof( SCROLLINFO ) );
sinfo.cbSize = sizeof( SCROLLINFO );
sinfo.fMask = SIF_POS;
snfo.nPos = scr_pos;
SetScrollInfo( hwnd, SB_VERT, & sinfo, TRUE );
}
}
break;
除了子控件外,什么都没有闪烁...
WS_CLIPCHILDREN
确实是解决方案。 继续并激活它,您必须找出“我的窗口的一部分弄乱了”的原因,但是您没有提供足够的细节。
您可能还会查看ScrollWindowEx
。 该文档专门描述了如何在滚动过程中正确地重新定位子窗口。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.