先大致介绍一下WINDOWS下的绘图原理:
我们在 Windows 环境下看到各种元素,如菜单、按钮、窗口、图像,从根本上说,都是“画”出来的。这时的屏幕,就相当于一块黑板,而 Windows 下的各种 GDI 要素,如画笔、画刷等,就相当于彩色粉笔了。我们在黑板上手工画图时,是一笔一划的,电脑亦然。只不过电脑的速度比手工快的太多,所以在我们看起来好像所有的图形文字都是同时出现的。
普通绘图方式的局限
上述绘图方式我们暂且称之为普通绘图方式吧。虽然这种方式能满足相当一部分的绘图需要,但是当要绘制的对象太复杂,尤其是含有位图时,电脑便力不从心了。这时的画面会显示的很慢,对于运动的画面,会给人“卡”住了的感觉,总之一个字:不爽。
解决之道:双缓冲
双缓冲的原理可以这样形象的理解:把电脑屏幕看作一块黑板。首先我们在内存环境中建立一个“虚拟“的黑板,然后在这块黑板上绘制复杂的图形,等图形全部绘制完毕的时候,再一次性的把内存中绘制好的图形“拷贝”到另一块黑板(屏幕)上。采取这种方法可以提高绘图速度,极大的改善绘图效果。下面是原理图:
双缓冲原理示意图
下面贴出代码吧
- #include <windows.h>
- #include "resource.h"
- LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
- void PThanshu(HWND);//普通画图函数
- void DHChanshu(HWND);//双缓冲画图函数
- int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
- PSTR szCmdLine, int iCmdShow)
- {
- static TCHAR szAppName [] = TEXT ("GDI") ;
- 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 (hInstance, MAKEINTRESOURCE(IDI_ICON1)) ;
- wndclass.hCursor = LoadCursor (NULL, IDC_ARROW) ;
- wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
- wndclass.lpszMenuName = szAppName;
- wndclass.lpszClassName = szAppName ;
- if (!RegisterClass (&wndclass))
- {
- MessageBox (NULL, TEXT ("This program requires Windows NT!"),
- szAppName, MB_ICONERROR) ;
- return 0 ;
- }
- hwnd = CreateWindow (szAppName, TEXT ("GDI TEST"),
- 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 ;
- }
- static int cxClient, cyClient;
- static int radius=1;
- LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
- {
- HDC hdc;
- HINSTANCE hInstance ;
- static int pt,gdi;//PT--普通画图,GDI--双缓冲画图
- PAINTSTRUCT ps ;
- RECT rect;
- TCHAR szAppName[]="GDI";
- switch (message)
- {
- case WM_CREATE:
- SetTimer(hwnd,1,1000,NULL);
- hInstance = ((LPCREATESTRUCT) lParam)->hInstance ;
- return 0 ;
- case WM_TIMER:
- //GetClientRect(hwnd,&rect);//本打算在这里触发WM_PAINT消息的
- // InvalidateRect(hwnd,&rect,TRUE);
- if(radius<16)
- {radius++;}
- else
- {radius=0;}
- if(pt)
- {
- PThanshu(hwnd);//普通画图
- }
- else if(gdi)
- {
- DHChanshu(hwnd);//双缓冲画图
- }
- else
- return 0;
- case WM_SIZE:
- //cxClient = LOWORD (lParam) ;
- //cyClient = HIWORD (lParam) ;
- return 0 ;
- case WM_PAINT:
- /*if(pt==1)
- {
- hdc = BeginPaint (hwnd, &ps) ;
- for(int x=0;x<cxClient;x+=16)
- for(int y=0;y<cyClient;y=+16)
- {
- Ellipse(hdc,x,y,x+radius,y+radius);
- }
- EndPaint (hwnd, &ps) ;
- }
- else
- {
- hdc=BeginPaint (hwnd, &ps) ;
- DrawText(hdc,szAppName,-1,&rect,DT_CENTER);
- EndPaint(hwnd,&ps);
- }*/
- hdc=BeginPaint(hwnd,&ps);
- GetClientRect(hwnd,&rect);
- DrawText(hdc,szAppName,-1,&rect,DT_CENTER);
- EndPaint(hwnd,&ps);
- return 0 ;
- case WM_COMMAND:
- if(lParam==0)
- {
- switch(wParam)
- {
- case IDM_PT://普通画图菜单项ID
- pt=1;
- gdi=0;
- return 0;
- case IDM_DHC://双缓冲画图菜单项ID
- gdi=1;
- pt=0;
- return 0;
- default:
- return 0;
- }
- }
- case WM_DESTROY:
- PostQuitMessage (0) ;
- return 0 ;
- }
- return DefWindowProc (hwnd, message, wParam, lParam) ;
- }
- void PThanshu(HWND hwnd)
- {
- HDC hdc=GetDC(hwnd);
- RECT rect;
- GetClientRect(hwnd,&rect);
- cxClient=rect.right;
- cyClient=rect.bottom;
- FillRect(hdc,&rect,NULL);
- for(int x=0;x<cxClient;x+=16)
- for(int y=0;y<cyClient;y+=16)
- {
- Ellipse(hdc,x,y,x+radius,y+radius);
- }
- ReleaseDC(hwnd,hdc);
- }
- void DHChanshu(HWND hwnd)//暂且没实现
- {
- //MessageBox(hwnd,TEXT("zhaoxujing"),TEXT("yiruirui"),MB_OK);
- HDC hdc=GetDC(hwnd);
- RECT rect;
- GetClientRect(hwnd,&rect);
- cxClient=rect.right;
- cyClient=rect.bottom;
- HDC hdcmem=CreateCompatibleDC(hdc);
- HBITMAP hbitmap=CreateCompatibleBitmap(hdc,cxClient,cyClient);
- SelectObject(hdcmem,hbitmap);
- FillRect(hdcmem,&rect,NULL);
- for(int x=0;x<cxClient;x+=16)
- for(int y=0;y<cyClient;y+=16)
- {
- Ellipse(hdcmem,x,y,x+radius,y+radius);
- }
- BitBlt(hdc,0,0,cxClient,cyClient,hdcmem,0,0,SRCCOPY);
- DeleteObject(hdcmem);
- ReleaseDC(hwnd,hdc);
- }
完整的工程放在了CSDN上,地址:http://download.csdn.net/source/2992685