VC双缓冲技术 以及绘图技术的一些注意点

以下是一个简单的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响应。

2.双缓冲的本质?
   比较简单的传统的重绘方式是:将原来的图全部清除掉,然后再画上新的图。这样会会出现闪烁的现象,因为清除掉的时候,屏幕是白色的(看设置的什么颜色),即在用户所需要的两个图中间,夹杂了一个莫名其妙的白屏,看上去显然不舒服。。。双缓冲的本质就是讲一个图像在一个BITMAP上完全画好,然后全部一下子先知道HDC上,这样就省去了清除的过程,所以看上去就不闪烁了。

3.不用Detele会内存泄露吗?
    会的,如果我SelectObject()了一个对象,而没有调用DetelteObject(),那么内存会不断增大,知道程序崩溃。通过任务管理器可以看到这一过程。

4.为什么有的时候使用BeginPaint函数后,屏幕会自动清屏呢?
    这是因为调用BeginPaint函数后,系统会产生一个 WM_ERASEBKGND的消息,而如果用户不对这个消息进行捕获处理,系统会默认执行刷屏操作。所以用户必须对 WM_ERASEBKGND消息自己控制处理,一般处理方式是什么都不干,直接break。如果不处理,屏幕还是会闪烁,那么双缓冲的目的就达不到了。

5.什么是无效区域?
  比如当前界面的一个区域被挡住了,这个被挡住的地方就叫做无效区域。当无效区域再次显示的时候,就会产生WM_PAINT消息。也可以手动将一个HDC设置为区域,这时当然也会自动产生WM_PAINT消息。

6. InvalidateRect(hwnd,NULL,1);是干嘛的?
    将整个DC区域设置成无效,目的就是为了产生一个WM_PAINT消息。第三个参数,设置会不会用画刷吧内容全部擦掉,false不会擦出,而true则会擦出。

你可能感兴趣的:(VC双缓冲技术 以及绘图技术的一些注意点)