如何编写减少闪烁的代码?需要您的代码帮助。 win32 VC++闪烁
我正在尝试使用鼠标 movemont.bitblt 位图到鼠标光标位置。但是存在闪烁问题。
我读过有关双缓冲以减少闪烁的内容,但我不知道如何...... 这会导致极度闪烁。我读过有关双缓冲以减少闪烁的内容,但我不确定如何在本例中实现它。 请问你能帮忙吗? 感谢
下面的代码。感谢您的帮助!
// screen blinks.trying to use double buffer so solve this problem.
#include <windows.h>
HDC bufferDC = NULL;
HDC hdc=GetWindowDC(NULL) ;
HDC hammerDC = NULL;
HBITMAP hammer1BMP = NULL;
HBITMAP bufferBMP = NULL;
POINT cursorpoint;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("DigClock") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Digital Clock"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
bufferDC=CreateCompatibleDC(hdc);
hammerDC=CreateCompatibleDC(hdc);
hammer1BMP=(HBITMAP)LoadImage(NULL,"star.bmp",IMAGE_BITMAP,160,160,LR_LOADFROMFILE);
SelectObject(hammerDC,hammer1BMP);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL f24Hour, fSuppress ;
static HBRUSH hBrushRed ;
static int cxClient, cyClient ;
HDC hdc ;
PAINTSTRUCT ps ;
TCHAR szBuffer [2] ;
switch (message)
{
case WM_CREATE:
hBrushRed = CreateSolidBrush (RGB (255, 0, 0)) ;
SetTimer (hwnd, ID_TIMER, 1000/24,NULL) ;//1000
// fall through
case WM_SETTINGCHANGE:
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_TIMER:
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
bufferBMP=CreateCompatibleBitmap(hdc,cxClient,cyClient);
SelectObject(bufferDC,bufferBMP);
// SelectObject(bufferDC,hammer1BMP);
GetCursorPos(&cursorpoint);
BitBlt(bufferDC,0,0,cxClient,cyClient,hammerDC,0,0,SRCCOPY);
BitBlt(hdc,cursorpoint.x,cursorpoint.y,cxClient,cyClient,bufferDC,0,0,SRCCOPY);
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_LBUTTONDOWN:
// GetCursorPos(&cursorpoint);
//BitBlt(hdc,cursorpoint.x,cursorpoint.y,cxClient,cyClient,hammerDC,0,0,SRCCOPY);
return 0;
case WM_DESTROY:
KillTimer (hwnd, ID_TIMER) ;
DeleteDC(hammerDC);
DeleteObject (hBrushRed) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
I'm trying to bitblt bitmap to mouse cursor position with the mouse movemont.but with flickering problems.
I've read about double buffering to reduce flicker but I'm not sure how to ...
this causes extreme flickering. I've read about double buffering to reduce flicker but I'm not sure how to implement it in this example.
Please can you help?
Thanks
here's code below .thanks for your help!
// screen blinks.trying to use double buffer so solve this problem.
#include <windows.h>
HDC bufferDC = NULL;
HDC hdc=GetWindowDC(NULL) ;
HDC hammerDC = NULL;
HBITMAP hammer1BMP = NULL;
HBITMAP bufferBMP = NULL;
POINT cursorpoint;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("DigClock") ;
HWND hwnd ;
MSG msg ;
WNDCLASS wndclass ;
wndclass.style = CS_HREDRAW | CS_VREDRAW ;
wndclass.lpfnWndProc = WndProc ;
wndclass.cbClsExtra = 0 ;
wndclass.cbWndExtra = 0 ;
wndclass.hInstance = hInstance ;
wndclass.hIcon = LoadIcon (NULL, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
wndclass.lpszMenuName = NULL ;
wndclass.lpszClassName = szAppName ;
if (!RegisterClass (&wndclass))
{
MessageBox (NULL, TEXT ("Program requires Windows NT!"),
szAppName, MB_ICONERROR) ;
return 0 ;
}
hwnd = CreateWindow (szAppName, TEXT ("Digital Clock"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
bufferDC=CreateCompatibleDC(hdc);
hammerDC=CreateCompatibleDC(hdc);
hammer1BMP=(HBITMAP)LoadImage(NULL,"star.bmp",IMAGE_BITMAP,160,160,LR_LOADFROMFILE);
SelectObject(hammerDC,hammer1BMP);
while (GetMessage (&msg, NULL, 0, 0))
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
return msg.wParam ;
}
LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static BOOL f24Hour, fSuppress ;
static HBRUSH hBrushRed ;
static int cxClient, cyClient ;
HDC hdc ;
PAINTSTRUCT ps ;
TCHAR szBuffer [2] ;
switch (message)
{
case WM_CREATE:
hBrushRed = CreateSolidBrush (RGB (255, 0, 0)) ;
SetTimer (hwnd, ID_TIMER, 1000/24,NULL) ;//1000
// fall through
case WM_SETTINGCHANGE:
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
case WM_SIZE:
cxClient = LOWORD (lParam) ;
cyClient = HIWORD (lParam) ;
return 0 ;
case WM_TIMER:
InvalidateRect (hwnd, NULL, TRUE) ;
return 0 ;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
bufferBMP=CreateCompatibleBitmap(hdc,cxClient,cyClient);
SelectObject(bufferDC,bufferBMP);
// SelectObject(bufferDC,hammer1BMP);
GetCursorPos(&cursorpoint);
BitBlt(bufferDC,0,0,cxClient,cyClient,hammerDC,0,0,SRCCOPY);
BitBlt(hdc,cursorpoint.x,cursorpoint.y,cxClient,cyClient,bufferDC,0,0,SRCCOPY);
EndPaint (hwnd, &ps) ;
return 0 ;
case WM_LBUTTONDOWN:
// GetCursorPos(&cursorpoint);
//BitBlt(hdc,cursorpoint.x,cursorpoint.y,cxClient,cyClient,hammerDC,0,0,SRCCOPY);
return 0;
case WM_DESTROY:
KillTimer (hwnd, ID_TIMER) ;
DeleteDC(hammerDC);
DeleteObject (hBrushRed) ;
PostQuitMessage (0) ;
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
在这种情况下,看起来您实际上并不需要双缓冲——事实上,它可能根本不会帮助您。
闪烁的主要原因是擦除背景,然后立即在其上绘制。由于您显然是在 WM_PAINT 中绘制窗口的整个客户区域,因此只需为 WM_ERASEBKGND 添加一个处理程序,该处理程序除了返回 TRUE 之外什么也不做,以指示背景已被删除。
编辑(回应评论):
为了更完整,闪烁的结果(几乎)任何时候你用一种颜色绘制一个区域,然后快速用另一种颜色重新绘制它。当/如果您的前景有许多不同颜色的重叠元素时,双缓冲会有所帮助。您将(至少)覆盖区域绘制到后台缓冲区中,然后只有当您拥有正确的颜色时,才将它们绘制到屏幕上。在这种情况下,原始代码执行双缓冲,但它仍然绘制背景,然后绘制前景,并且仍然会闪烁。
另一个答案提到将 false 作为第二个参数传递给 InvalidateRect。这将有很大帮助,因为它不会重新绘制背景以响应 InvalidateRect。仅绘制前景,因此不会闪烁。不幸的是,当窗口的矩形(至少部分)由于任何其他原因而无效时,您仍然会出现闪烁,因为它仍然会绘制背景,然后绘制前景。
In this case it looks like you don't really need double buffering -- in fact, it probably won't help you at all.
The primary cause of your flickering is erasing the background, then immediately drawing over it. Since you're apparently drawing the whole client area of your window in WM_PAINT, just add a handler for WM_ERASEBKGND that does nothing but return TRUE to indicate that the background has been erased.
Edit (in response to comments):
To be more complete, flickering results (almost) anytime you paint an area in one color, then quickly repaint it in another color. Double buffering helps when/if your foreground has a number of overlaying elements of different colors. You draw (at least the) overlaying areas into the back buffer, then only when you have the right colors, you draw them to the screen. In this case, the original code does double buffering, but it's still drawing the background, then the foreground, and you still get flickering.
Another answer mentioned passing false as the second parameter to InvalidateRect. This will help a lot, as it won't re-draw the background in response to that InvalidateRect. Only he foreground will be drawn, so it'll be flicker-free. Unfortunately, when (at least part of) the Window's rectangle is invalidated for any other reason, you'll still get flicker, because it'll still draw the background followed by the foreground.
删除你的计时器。即使窗口没有更改,计时器也会导致您无效。此外,每次计时器结束时您都会擦除窗口。
基本上,你的概念是正确的。当您需要 WM_PAINT 时,复制您的后台缓冲区。当您需要更新图形时,更新您的后台缓冲区,然后仅无效一次。
另一个技巧是使用 GetUpdateRect() 来获取 WM_PAINT 中的更新区域。只复制后台缓冲区中脏的区域。这进一步优化了您的双缓冲
Remove your timer. The timer is causing you to invalidate even when there is no change to the window. Furthermore, you are erasing the window with each timer elapse.
Basically , you got the concept correct. When you need to WM_PAINT, copy your back buffer. When you need to update the graphics, update your back buffer and then only invalidate once.
Another tip is to use GetUpdateRect() to get the update region in WM_PAINT. Only copy the region which is dirty from your back buffer. This further optimizes your double buffering
闪烁(以及最终程序崩溃)的原因是多方面的:
The cause of the flicker (and eventual program crash) is multifold:
为了避免闪烁,请使用双缓冲方法。
在此方法中,我们在屏幕外 DC (hdcBuffer) 上执行绘制过程,然后将该 DC 的内容复制到实际屏幕 DC (hdc) 。还可以通过向 WM_ERASEBKGND 消息返回非零来避免擦除背景。
这是算法:
To avoid flickering use double buffering method.
In this method we do painting procedure over off screen DC (hdcBuffer) and then copy the content of that DC to actual screen DC (hdc). Also avoid erasing of background by returning non zero to WM_ERASEBKGND message.
Here is the algo: