前面的程序碰到刷新时碰到闪烁问题,百度一搜,一堆关于双缓冲解决闪烁的文章。
具体实施方案为:
1、建立一个内存DC
hdcMem = CreateCompatibleDC(hdc);
此时,内存DC的显示表面是单色、1个像素宽、1个像素高。即显示表面仅仅1位。
2、CreateCompatibleBitmap创建一个与设备兼容的位图,
::GetClientRect(hwnd, &rc);
hBitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top);
3、把画布对象选入内存DC
SelectObject(hdcMem, hBitmap);
4、将内存DC中的图一次性丢给DC,或则将DC中的图丢给内存DC
BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY);
BitBlt(hdcMem, 0, 0, cxClient, cyClient, hdc, 0, 0, SRCCOPY);
在用本方法改进前面的CAD程序碰到的问题
1、初始化时 ,将当前hdc内容丢给内存DC,BitBlt语句的位置。
a、放在WM_CREATE消息中,里面的内容是黑色的;
b、只有放置在WM_SIZE或WM_PAINT消息内,内容才和DC一样是白色(注意hdc的释放及申请);
从上述两点,可以看出,创建窗口时,windows系统并没有绘制窗口。跟踪发现,CreateWindow执行完毕,窗口并未绘制,而是在后面的ShowWindow时窗口完成了绘制,此刻后进入了WM_SIZE消息,所以此时hdc内是有内容的,同理WM_PAINT发生在后面,hdc也是有内容。
2、刚开始改动时,延续了前面程序的做法,所有更新都在WM_PAINT中进行,无法避免闪烁。后面将绘制过程在响应消息内完成,就好了。
/*--------------------------------------------------
利用BitBlt来刷新
--------------------------------------------------*/
#include <windows.h>
#include <windowsx.h>
#include <vector>
using std::vector;
vector<POINT> pt;
enum LineStyle {HeavyLine, LightLine, DashLine};
struct line
{
POINT ptStart;
POINT ptEnd;
enum LineStyle lineStyel;
};
vector<line> lines;
vector<line> lines_scaled;
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
PSTR szCmdLine, int iCmdShow)
{
static TCHAR szAppName[] = TEXT ("MyCAD") ;
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 ("MyCAD"),
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, hInstance, NULL) ;
ShowWindow (hwnd, iCmdShow) ;
UpdateWindow (hwnd) ;
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 int iCount =0;
static int cxClient, cyClient;
static float scaleratio = 1;
static HPEN hPen[3];
static HBITMAP hBitmap, hBitmapTmp;
static HDC hdcMem, hdcMemTmp;
static RECT rc;
static BOOL flagCreate;
static BOOL flagClicked;
line lineTmp;
HDC hdc;
PAINTSTRUCT ps ;
static POINT aptStart = {0,0}, aptEnd = { 0,0 }, aptCurrent;
static BOOL fdraw = 0;
switch (message)
{
case WM_CREATE:
flagCreate = TRUE;
hdc = GetDC(hwnd);
::GetClientRect(hwnd, &rc);
hdcMem = CreateCompatibleDC(hdc);
hBitmap = CreateCompatibleBitmap(hdc, rc.right-rc.left, rc.bottom-rc.top);
hdcMemTmp = CreateCompatibleDC(hdc);
hBitmapTmp = CreateCompatibleBitmap(hdc, rc.right - rc.left, rc.bottom - rc.top);
SelectObject(hdcMem, hBitmap);
SelectObject(hdcMemTmp, hBitmapTmp);
SelectObject(hdcMemTmp, hPen[1]);
hPen[0] = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
hPen[1] = CreatePen(PS_SOLID, 1, RGB(0, 255, 0));
hPen[2] = CreatePen(PS_DASH, 1, RGB(0, 0, 0));
//此时hdc内没有内容,将得到全黑图像
//BitBlt(hdcMem, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
//BitBlt(hdcMemTmp, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hdc);
return 0;
case WM_SIZE:
cxClient = LOWORD(lParam);
cyClient = HIWORD(lParam);
//此时hdc内有内容,可以正常使用
//hdc = GetDC(hwnd);
//BitBlt(hdcMem, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
//BitBlt(hdcMemTmp, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
//ReleaseDC(hwnd, hdc);
return 0;
case WM_LBUTTONDOWN:
aptEnd.x = GET_X_LPARAM(lParam);
aptEnd.y = GET_Y_LPARAM(lParam);
if (fdraw != 0)
{
lineTmp.ptStart = aptStart;
lineTmp.ptEnd = aptEnd;
lineTmp.lineStyel = HeavyLine;
lines.push_back(lineTmp);
iCount++;
}
else
{
aptStart = aptEnd;
SetPixel(hdcMem, aptStart.x, aptStart.y, 0);
fdraw = 1;
return 0;
}
MoveToEx(hdcMem, aptStart.x, aptStart.y, NULL);
LineTo(hdcMem, aptEnd.x, aptEnd.y);
hdc = GetDC(hwnd);
BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMemTmp, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hdc);
aptStart = aptEnd;
if (!lines_scaled.empty())
lines_scaled.clear();
lines_scaled = lines;
return 0 ;
case WM_RBUTTONDOWN:
fdraw = 0;
InvalidateRect(hwnd, NULL, TRUE);
return 0;
case WM_MOUSEMOVE:
if (fdraw)
{
aptEnd.x = GET_X_LPARAM(lParam);
aptEnd.y = GET_Y_LPARAM(lParam);
BitBlt(hdcMemTmp, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY);
MoveToEx(hdcMemTmp, aptStart.x, aptStart.y, NULL);
LineTo(hdcMemTmp, aptEnd.x, aptEnd.y);
hdc = GetDC(hwnd);
BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMemTmp, 0, 0, SRCCOPY);
ReleaseDC(hwnd, hdc);
}
aptCurrent.x= GET_X_LPARAM(lParam);
aptCurrent.y = GET_Y_LPARAM(lParam);
return 0 ;
case WM_MOUSEWHEEL:
if (!lines_scaled.empty())
{
if ((short)HIWORD(wParam)>0)
{
scaleratio = 1.25;
}
else
{
scaleratio = 0.8;
}
for (int i = 0;i < (int)lines_scaled.size();i++)
{
lines_scaled[i].ptStart.x = scaleratio*(lines_scaled[i].ptStart.x - aptCurrent.x) + aptCurrent.x;
lines_scaled[i].ptStart.y = scaleratio*(lines_scaled[i].ptStart.y - aptCurrent.y) + aptCurrent.y;
lines_scaled[i].ptEnd.x = scaleratio*(lines_scaled[i].ptEnd.x - aptCurrent.x) + aptCurrent.x;
lines_scaled[i].ptEnd.y = scaleratio*(lines_scaled[i].ptEnd.y - aptCurrent.y) + aptCurrent.y;
}
hdc = GetDC(hwnd);
Rectangle(hdc,0,0, cxClient, cyClient);
for (int i = 0; i < (int)lines_scaled.size(); i++)
{
MoveToEx(hdc, lines_scaled[i].ptStart.x, lines_scaled[i].ptStart.y, NULL);
LineTo(hdc, lines_scaled[i].ptEnd.x, lines_scaled[i].ptEnd.y);
}
ReleaseDC(hwnd, hdc);
}
BitBlt(hdcMem, 0, 0, cxClient, cyClient, hdc, 0, 0, SRCCOPY);
BitBlt(hdcMemTmp, 0, 0, cxClient, cyClient, hdc, 0, 0, SRCCOPY);
return 0;
case WM_PAINT:
hdc = BeginPaint (hwnd, &ps) ;
if (flagCreate)
{
BitBlt(hdcMem, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
BitBlt(hdcMemTmp, 0, 0, rc.right - rc.left, rc.bottom - rc.top, hdc, 0, 0, SRCCOPY);
flagCreate = FALSE;
return 0;
}
BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY);
EndPaint (hwnd, &ps) ;
return 0;
case WM_DESTROY:
PostQuitMessage (0) ;
DeleteObject(hPen[0]);
DeleteObject(hPen[1]);
DeleteObject(hPen[2]);
DeleteDC(hdcMem);
DeleteObject(hBitmap);
DeleteDC(hdcMemTmp);
DeleteObject(hBitmapTmp);
return 0 ;
}
return DefWindowProc (hwnd, message, wParam, lParam) ;
}