以下是一个简单的VC消息循环程序,使用双缓冲技术实现显示。在该程序后对于该VC的一些基本知识进行介绍。
#include
<windows.h>
LRESULT CALLBACK WinTestProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam);
void
CALLBACK MyTimerFun(HWND, UINT, UINT_PTR, DWORD);
void
OnDraw(HWND hwnd);
int
cnt=0;
int
WINAPI WinMain(
HINSTANCE hInstance,
// handle to current instance
HINSTANCE hPrevInstance,
// handle to previous instance
LPSTR lpCmdLine,
// command line
int
nCmdShow
// show state
)
{
WNDCLASS wndcls;
wndcls.cbClsExtra=0;
wndcls.cbWndExtra=0;
wndcls.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);
wndcls.hCursor=LoadCursor(NULL,IDC_ARROW);
wndcls.hIcon=LoadIcon(NULL, IDI_APPLICATION);
wndcls.hInstance=hInstance;
wndcls.lpfnWndProc=WinTestProc;
wndcls.lpszClassName=L
"Test"
;
wndcls.lpszMenuName=NULL;
wndcls.style=CS_HREDRAW | CS_VREDRAW;
RegisterClass(&wndcls);
HWND hwnd;
hwnd=CreateWindow(L
"Test"
,L
"Test"
,WS_SYSMENU|WS_MINIMIZEBOX,0,0,400,400,NULL,NULL,hInstance,NULL);
ShowWindow(hwnd,SW_SHOWNORMAL);
UpdateWindow(hwnd);
SetTimer(hwnd,1,100,MyTimerFun);
MSG msg;
while
(GetMessage(&msg,NULL,0,0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return
0;
}
LRESULT CALLBACK WinTestProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch
(uMsg)
{
case
WM_KEYDOWN:
break
;
case
WM_PAINT:
OnDraw(hwnd);
break
;
case
WM_CLOSE:
DestroyWindow(hwnd);
break
;
case
WM_DESTROY:
PostQuitMessage(0);
break
;
case
WM_ERASEBKGND:
break
;
default
:
return
DefWindowProc(hwnd,uMsg,wParam,lParam);
}
return
0;
}
void
CALLBACK MyTimerFun(HWND hwnd, UINT, UINT_PTR, DWORD)
{
InvalidateRect(hwnd,NULL,1);
}
void
OnDraw( HWND hwnd )
{
PAINTSTRUCT ps;
HDC hdc=BeginPaint(hwnd,&ps);
HBRUSH hBr;
HPEN hP;
//定义画笔
if
( cnt%2==0 )
hBr=CreateSolidBrush(RGB(255,0,0));
else
hBr=CreateSolidBrush(RGB(0,255,0));
//定义画刷
if
(cnt%2==0)
hP=CreatePen(PS_SOLID,11,RGB(0,0,255));
//自定义画笔
else
hP=CreatePen(PS_SOLID,11,RGB(55,30,100));
//自定义画笔
cnt++;
//创建一个位图
HBITMAP bit = CreateCompatibleBitmap(hdc,300,300);
HDC MemDC = CreateCompatibleDC(hdc);
//BITMAP HPEN HBRUSH 是同等地位?的
SelectObject(MemDC,bit);
SelectObject(MemDC,hP);
SelectObject(MemDC,hBr);
//RECT r;r.top=0;r.bottom=300;r.left=0;r.right=300;
//FillRect(MemDC,&r,hBr); 刷屏
LineTo(MemDC,200,200);
Ellipse(MemDC,20,40,320,200);
//从???内??存??到??hdc描??述??符??
BitBlt(hdc,0,0,300,300,MemDC,0,0,SRCCOPY);
DeleteObject(hP);
DeleteObject(hBr);
DeleteObject(bit);
DeleteDC(MemDC);
EndPaint(hwnd,&ps);
}
1.为什么WM_PAINT中只能用 BeginPaint & EndPaint,而不能使用GetDC()和ReleaseDC()?
当程序产生一个重绘消息的时候,进程消息对列会增加这一消息(就是WM_PAINT消息)。而BeginPaint的功能就是清除这个MSG。而如果用GetDC(),则不能清除这个MSG,因此WMPAINT会一直在消息队列中,所以就会不断的有WMPAINT响应。
比较简单的传统的重绘方式是:将原来的图全部清除掉,然后再画上新的图。这样会会出现闪烁的现象,因为清除掉的时候,屏幕是白色的(看设置的什么颜色),即在用户所需要的两个图中间,夹杂了一个莫名其妙的白屏,看上去显然不舒服。。。双缓冲的本质就是讲一个图像在一个BITMAP上完全画好,然后全部一下子先知道HDC上,这样就省去了清除的过程,所以看上去就不闪烁了。
会的,如果我SelectObject()了一个对象,而没有调用DetelteObject(),那么内存会不断增大,知道程序崩溃。通过任务管理器可以看到这一过程。