windows GDI和GDI+对比小结
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了windows GDI和GDI+对比小结,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含22365字,纯文字阅读大概需要32分钟。
内容图文
![windows GDI和GDI+对比小结](/upload/InfoBanner/zyjiaocheng/1132/278f18c38be4458ea0ca285752a6ebdd.jpg)
目录结构
windows
1.windows hello world。
2.windows程序消息队列机制。
GDI
1.画一个点。
2.设备环境DC。
3.画线、矩形、圆角矩形、椭圆。
4.画笔。
5.画刷。
6.GDI对象还原。
GDI+
1.使用GDI+。
2.GDI和GDI+绘制对比。
3.GDI+渐变填充、位图填充。
内存DC
微软Windows子系统负责在称为图形设备接口(Graphics Device Interface, GDI)的视频显示器和打印机上显示图形。 ——《Windows程序设计(第五版)》
GDI+是早期Windows版本中包括的图形设备接口GDI的继任者。GDI+将GDI的很多功能进行了优化,而且提供了新的附加功能。
——《精通GDI+编程》
1.windows程序运行hello world。只需要在vs下新建一个空项目,输入以下代码,即可出现hello world。
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 #include <Windows.h>
2 3LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
4 5int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
6 PSTR szCmdLine, int iCmdShow)
7{
8 9 TCHAR szAppName[] = TEXT("Hello");
10 WNDCLASS wndclass;
11 wndclass.style = CS_HREDRAW | CS_VREDRAW;
12 wndclass.lpfnWndProc = WndProc;
13 wndclass.cbClsExtra = 0;
14 wndclass.cbWndExtra = 0;
15 wndclass.hInstance = hInstance;
16 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
17 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
18 wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
19 wndclass.lpszMenuName = NULL;
20 wndclass.lpszClassName = szAppName;
2122if (!RegisterClass(&wndclass))
23 {
24 MessageBox(NULL, TEXT("error"), szAppName, MB_ICONERROR);
25return0;
26 }
2728 HWND hwnd = CreateWindow(szAppName,
29 TEXT("Hello"),
30 WS_OVERLAPPEDWINDOW,
31 CW_USEDEFAULT, CW_USEDEFAULT,
32 CW_USEDEFAULT, CW_USEDEFAULT,
33 NULL,
34 NULL,
35 hInstance,
36 NULL);
3738 ShowWindow(hwnd, iCmdShow);
39 UpdateWindow(hwnd);
4041 MSG msg;
42while (GetMessage(&msg, NULL, 0, 0))
43 {
44 TranslateMessage(&msg);
45 DispatchMessage(&msg);
46 }
47return msg.wParam;
48}
4950LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
51{
52 HDC hdc;
53 PAINTSTRUCT ps;
54 TCHAR text[30];
55switch (msg)
56 {
57case WM_CREATE:
58return0;
59case WM_PAINT:
60 hdc = BeginPaint(hwnd, &ps);
61 TextOut(hdc, 100, 100, text, wsprintf(text, TEXT("HELLO WORLD")));
62 EndPaint(hwnd, &ps);
63return0;
64case WM_DESTROY:
65 PostQuitMessage(0);
66return0;
67 }
68return DefWindowProc(hwnd, msg, wParam, lParam);
69 }
2.windows程序的运行本质是消息队列机制。
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1
MSG msg;
2
while (GetMessage(&msg, NULL, 0, 0))
3 {
4 TranslateMessage(&msg);
5 DispatchMessage(&msg);
6 }
windows程序不停地检测消息队列中是否有新的消息,
while (GetMessage(&msg, NULL, 0, 0)),若消息队列中没有消息,则程序会阻塞;
若消息队列中有消息:
对于所有非WM_QUIT消息,GetMessage函数都将返回非零值,
而对WM_QUIT消息,GetMessage将返回0,则退出消息循环。
在此模型中,其实有两个队列。
一个是操作系统队列,事件发生时(比如按键盘的某个键),在操作系统的队列会插入一个相应的事件消息。
接着操作系统队列会把此消息传递给windows程序的消息队列。
GDI
1.首先我们往窗口上画一个点。
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 #include <Windows.h>
2 3LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
4 5int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
6 PSTR szCmdLine, int iCmdShow)
7{
8 9 TCHAR szAppName[] = TEXT("Hello");
10 WNDCLASS wndclass;
11 wndclass.style = CS_HREDRAW | CS_VREDRAW;
12 wndclass.lpfnWndProc = WndProc;
13 wndclass.cbClsExtra = 0;
14 wndclass.cbWndExtra = 0;
15 wndclass.hInstance = hInstance;
16 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
17 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
18 wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
19 wndclass.lpszMenuName = NULL;
20 wndclass.lpszClassName = szAppName;
2122if (!RegisterClass(&wndclass))
23 {
24 MessageBox(NULL, TEXT("error"), szAppName, MB_ICONERROR);
25return0;
26 }
2728 HWND hwnd = CreateWindow(szAppName,
29 TEXT("Hello"),
30 WS_OVERLAPPEDWINDOW,
31 CW_USEDEFAULT, CW_USEDEFAULT,
32 CW_USEDEFAULT, CW_USEDEFAULT,
33 NULL,
34 NULL,
35 hInstance,
36 NULL);
3738 ShowWindow(hwnd, iCmdShow);
39 UpdateWindow(hwnd);
4041 MSG msg;
42while (GetMessage(&msg, NULL, 0, 0))
43 {
44 TranslateMessage(&msg);
45 DispatchMessage(&msg);
46 }
47return msg.wParam;
48}
4950LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
51{
52 HDC hdc;
53 PAINTSTRUCT ps;
54switch (msg)
55 {
56case WM_CREATE:
57return0;
58case WM_PAINT:
59 hdc = BeginPaint(hwnd, &ps);
60 SetPixel(hdc, 400, 400, 0x000000ff);
61 EndPaint(hwnd, &ps);
62return0;
63case WM_DESTROY:
64 PostQuitMessage(0);
65return0;
66 }
67return DefWindowProc(hwnd, msg, wParam, lParam);
68 }
核心GDI函数是SetPixel,函数的参数列表依次是设备环境句柄,x,y坐标和颜色。
这里颜色是一个DWORD的数值。(0x00bbggrr,从右往左依次为rgb值,如红色是0x000000ff)
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1
COLORREF SetPixel(
2
HDC hdc,
3
int
X,
4
int
Y,
5
COLORREF crColor
6 );
2.设备环境DC
SetPixel写在WM_PAINT消息的处理中,WM_PAINT处理处有成对出现的
hdc = BeginPaint(hwnd, &ps);
// other code
EndPaint(hwnd, &ps);
这便是使用GDI函数时必经的一个步骤,获取设备环境句柄(HDC),可见GDI函数的参数列表中都有一个HDC。
除了在WM_PAINT中的BeginPaint和EndPaint,在非WM_PAINT消息中获取DC的常用方式还有:
hdc = GetDC(hwnd);
// other code
ReleaseDC(hwnd, hdc);
比如点击鼠标的时候画一个红点,此操作不在WM_PAINT消息中处理,在WM_LBUTTONDOWN消息中处理:
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 #include <Windows.h> 2 3LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 4 5int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 6 PSTR szCmdLine, int iCmdShow) 7{ 8 9 TCHAR szAppName[] = TEXT("Hello"); 10 WNDCLASS wndclass; 11 wndclass.style = CS_HREDRAW | CS_VREDRAW; 12 wndclass.lpfnWndProc = WndProc; 13 wndclass.cbClsExtra = 0; 14 wndclass.cbWndExtra = 0; 15 wndclass.hInstance = hInstance; 16 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 18 wndclass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); 19 wndclass.lpszMenuName = NULL; 20 wndclass.lpszClassName = szAppName; 2122if (!RegisterClass(&wndclass)) 23 { 24 MessageBox(NULL, TEXT("error"), szAppName, MB_ICONERROR); 25return0; 26 } 2728 HWND hwnd = CreateWindow(szAppName, 29 TEXT("Hello"), 30 WS_OVERLAPPEDWINDOW, 31 CW_USEDEFAULT, CW_USEDEFAULT, 32 CW_USEDEFAULT, CW_USEDEFAULT, 33 NULL, 34 NULL, 35 hInstance, 36 NULL); 3738 ShowWindow(hwnd, iCmdShow); 39 UpdateWindow(hwnd); 4041 MSG msg; 42while (GetMessage(&msg, NULL, 0, 0)) 43 { 44 TranslateMessage(&msg); 45 DispatchMessage(&msg); 46 } 47return msg.wParam; 48} 4950LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 51{ 52 HDC hdc; 53 PAINTSTRUCT ps; 54int x = 0, y = 0; 55switch (msg) 56 { 57case WM_CREATE: 58return0; 59case WM_PAINT: 60 hdc = BeginPaint(hwnd, &ps); 61// SetPixel(hdc, 400, 400, 0x000000ff);62 EndPaint(hwnd, &ps); 63return0; 64case WM_LBUTTONDOWN: 65 hdc = GetDC(hwnd); 66 x = LOWORD(lParam); 67 y = HIWORD(lParam); 68 SetPixel(hdc, x, y, 0x000000ff); 69 ReleaseDC(hwnd, hdc); 70return0; 71case WM_DESTROY: 72 PostQuitMessage(0); 73return0; 74 } 75return DefWindowProc(hwnd, msg, wParam, lParam); 76 }
有了以上的基础,接着可以来看下一些画线的GDI函数:
3.画线、矩形、圆角矩形、椭圆。
画直线MoveToEx,LineTo:
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 #include <Windows.h> 2 3LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 4 5int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 6 PSTR szCmdLine, int iCmdShow) 7{ 8 9 TCHAR szAppName[] = TEXT("Hello"); 10 WNDCLASS wndclass; 11 wndclass.style = CS_HREDRAW | CS_VREDRAW; 12 wndclass.lpfnWndProc = WndProc; 13 wndclass.cbClsExtra = 0; 14 wndclass.cbWndExtra = 0; 15 wndclass.hInstance = hInstance; 16 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 18 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 19 wndclass.lpszMenuName = NULL; 20 wndclass.lpszClassName = szAppName; 2122if (!RegisterClass(&wndclass)) 23 { 24 MessageBox(NULL, TEXT("error"), szAppName, MB_ICONERROR); 25return0; 26 } 2728 HWND hwnd = CreateWindow(szAppName, 29 TEXT("Hello"), 30 WS_OVERLAPPEDWINDOW, 31 CW_USEDEFAULT, CW_USEDEFAULT, 32 CW_USEDEFAULT, CW_USEDEFAULT, 33 NULL, 34 NULL, 35 hInstance, 36 NULL); 3738 ShowWindow(hwnd, iCmdShow); 39 UpdateWindow(hwnd); 4041 MSG msg; 42while (GetMessage(&msg, NULL, 0, 0)) 43 { 44 TranslateMessage(&msg); 45 DispatchMessage(&msg); 46 } 47return msg.wParam; 48} 4950LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 51{ 52 HDC hdc; 53 PAINTSTRUCT ps; 54staticint cxClient = 0, cyClient = 0; 55switch (msg) 56 { 57case WM_CREATE: 58return0; 59case WM_SIZE: 60 cxClient = LOWORD(lParam); 61 cyClient = HIWORD(lParam); 62return0; 63case WM_PAINT: 64 hdc = BeginPaint(hwnd, &ps); 65 MoveToEx(hdc, 0, cyClient / 2, NULL); 66 LineTo(hdc, cxClient, cyClient / 2); 67 EndPaint(hwnd, &ps); 68return0; 69case WM_LBUTTONDOWN: 70return0; 71case WM_DESTROY: 72 PostQuitMessage(0); 73return0; 74 } 75return DefWindowProc(hwnd, msg, wParam, lParam); 76 }
画一个由多个点的数组组成的折线PolyLine:
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 #include <Windows.h> 2 #include <math.h> 3 4LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 5 6int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 7 PSTR szCmdLine, int iCmdShow) 8{ 910 TCHAR szAppName[] = TEXT("Hello"); 11 WNDCLASS wndclass; 12 wndclass.style = CS_HREDRAW | CS_VREDRAW; 13 wndclass.lpfnWndProc = WndProc; 14 wndclass.cbClsExtra = 0; 15 wndclass.cbWndExtra = 0; 16 wndclass.hInstance = hInstance; 17 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 18 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 19 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 20 wndclass.lpszMenuName = NULL; 21 wndclass.lpszClassName = szAppName; 2223if (!RegisterClass(&wndclass)) 24 { 25 MessageBox(NULL, TEXT("error"), szAppName, MB_ICONERROR); 26return0; 27 } 2829 HWND hwnd = CreateWindow(szAppName, 30 TEXT("Hello"), 31 WS_OVERLAPPEDWINDOW, 32 CW_USEDEFAULT, CW_USEDEFAULT, 33 CW_USEDEFAULT, CW_USEDEFAULT, 34 NULL, 35 NULL, 36 hInstance, 37 NULL); 3839 ShowWindow(hwnd, iCmdShow); 40 UpdateWindow(hwnd); 4142 MSG msg; 43while (GetMessage(&msg, NULL, 0, 0)) 44 { 45 TranslateMessage(&msg); 46 DispatchMessage(&msg); 47 } 48return msg.wParam; 49} 5051LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 52{ 53 HDC hdc; 54 PAINTSTRUCT ps; 55staticint cxClient = 0, cyClient = 0; 56conststaticint NUM = 1000; 57conststaticfloat TWOPI = 2 * 3.1415926; 58 POINT apt[NUM]; 59switch (msg) 60 { 61case WM_CREATE: 62return0; 63case WM_SIZE: 64 cxClient = LOWORD(lParam); 65 cyClient = HIWORD(lParam); 66return0; 67case WM_PAINT: 68 hdc = BeginPaint(hwnd, &ps); 69 MoveToEx(hdc, 0, cyClient / 2, NULL); 70 LineTo(hdc, cxClient, cyClient / 2); 7172for (int i = 0; i < NUM; ++i) 73 { 74 apt[i].x = i * cxClient / NUM; 75 apt[i].y = (int)(cyClient / 2 * (1 - sin(TWOPI * i / NUM))); 76 } 7778 Polyline(hdc, apt, NUM); 79 EndPaint(hwnd, &ps); 80return0; 81case WM_LBUTTONDOWN: 82return0; 83case WM_DESTROY: 84 PostQuitMessage(0); 85return0; 86 } 87return DefWindowProc(hwnd, msg, wParam, lParam); 88 }
画一个矩形Rectangle,圆角矩形RoundRect,椭圆Ellipse:
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 #include <Windows.h> 2 3LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 4 5int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 6 PSTR szCmdLine, int iCmdShow) 7{ 8 9 TCHAR szAppName[] = TEXT("Hello"); 10 WNDCLASS wndclass; 11 wndclass.style = CS_HREDRAW | CS_VREDRAW; 12 wndclass.lpfnWndProc = WndProc; 13 wndclass.cbClsExtra = 0; 14 wndclass.cbWndExtra = 0; 15 wndclass.hInstance = hInstance; 16 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 18 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 19 wndclass.lpszMenuName = NULL; 20 wndclass.lpszClassName = szAppName; 2122if (!RegisterClass(&wndclass)) 23 { 24 MessageBox(NULL, TEXT("error"), szAppName, MB_ICONERROR); 25return0; 26 } 2728 HWND hwnd = CreateWindow(szAppName, 29 TEXT("Hello"), 30 WS_OVERLAPPEDWINDOW, 31 CW_USEDEFAULT, CW_USEDEFAULT, 32 CW_USEDEFAULT, CW_USEDEFAULT, 33 NULL, 34 NULL, 35 hInstance, 36 NULL); 3738 ShowWindow(hwnd, iCmdShow); 39 UpdateWindow(hwnd); 4041 MSG msg; 42while (GetMessage(&msg, NULL, 0, 0)) 43 { 44 TranslateMessage(&msg); 45 DispatchMessage(&msg); 46 } 47return msg.wParam; 48} 4950LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 51{ 52 HDC hdc; 53 PAINTSTRUCT ps; 54staticint cxClient = 0, cyClient = 0; 55switch (msg) 56 { 57case WM_CREATE: 58return0; 59case WM_SIZE: 60 cxClient = LOWORD(lParam); 61 cyClient = HIWORD(lParam); 62return0; 63case WM_PAINT: 64 hdc = BeginPaint(hwnd, &ps); 6566 Rectangle(hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8); 67 Ellipse(hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8); 68 RoundRect(hdc, cxClient / 4, cyClient / 4, 3 * cxClient / 4, 3 * cyClient / 4, cxClient / 4, cyClient / 4); 6970 EndPaint(hwnd, &ps); 71return0; 72case WM_LBUTTONDOWN: 73return0; 74case WM_DESTROY: 75 PostQuitMessage(0); 76return0; 77 } 78return DefWindowProc(hwnd, msg, wParam, lParam); 79 }
还有其余的用法都是类似,有需要去查msdn就行。
4.画笔
前面画线使用的都是默认的画笔。Windows提供了三种备用画笔:WHITE_PEN,BLACK_PEN,NULL_PEN。
如果想要其他类型的画笔,则需要自己创建,使用CreatePen或CreatePenIndirect。
还是前面的画矩形、画圆角矩形、画椭圆的例子。这次用绿色的虚线来画。
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 #include <Windows.h> 2 3LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 4 5int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 6 PSTR szCmdLine, int iCmdShow) 7{ 8 9 TCHAR szAppName[] = TEXT("Hello"); 10 WNDCLASS wndclass; 11 wndclass.style = CS_HREDRAW | CS_VREDRAW; 12 wndclass.lpfnWndProc = WndProc; 13 wndclass.cbClsExtra = 0; 14 wndclass.cbWndExtra = 0; 15 wndclass.hInstance = hInstance; 16 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 18 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 19 wndclass.lpszMenuName = NULL; 20 wndclass.lpszClassName = szAppName; 2122if (!RegisterClass(&wndclass)) 23 { 24 MessageBox(NULL, TEXT("error"), szAppName, MB_ICONERROR); 25return0; 26 } 2728 HWND hwnd = CreateWindow(szAppName, 29 TEXT("Hello"), 30 WS_OVERLAPPEDWINDOW, 31 CW_USEDEFAULT, CW_USEDEFAULT, 32 CW_USEDEFAULT, CW_USEDEFAULT, 33 NULL, 34 NULL, 35 hInstance, 36 NULL); 3738 ShowWindow(hwnd, iCmdShow); 39 UpdateWindow(hwnd); 4041 MSG msg; 42while (GetMessage(&msg, NULL, 0, 0)) 43 { 44 TranslateMessage(&msg); 45 DispatchMessage(&msg); 46 } 47return msg.wParam; 48} 4950LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 51{ 52 HDC hdc; 53 PAINTSTRUCT ps; 54staticint cxClient = 0, cyClient = 0; 55static HPEN hPen; 56switch (msg) 57 { 58case WM_CREATE: 59return0; 60case WM_SIZE: 61 cxClient = LOWORD(lParam); 62 cyClient = HIWORD(lParam); 63return0; 64case WM_PAINT: 65 hdc = BeginPaint(hwnd, &ps); 66 hPen = CreatePen(PS_DASH, 1, 0x0000ff00); 67 SelectObject(hdc, hPen); 68 Rectangle(hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8); 69 Ellipse(hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8); 70 RoundRect(hdc, cxClient / 4, cyClient / 4, 3 * cxClient / 4, 3 * cyClient / 4, cxClient / 4, cyClient / 4); 71 DeleteObject(hPen); 72 EndPaint(hwnd, &ps); 73return0; 74case WM_LBUTTONDOWN: 75return0; 76case WM_DESTROY: 77 PostQuitMessage(0); 78return0; 79 } 80return DefWindowProc(hwnd, msg, wParam, lParam); 81 }
创建了画笔要记得删除画笔。
hPen = CreatePen(PS_DASH, 1, 0x0000ff00);
SelectObject(hdc, hPen);
// other code
DeleteObject(hPen);
5.画刷。
前面类似圆角矩形的区域,用到的画刷都是默认的画刷。Windows提供了6种备用画刷。
如果想要给一片区域填充某一种颜色,比如一片绿色的圆角矩形区域。此时用到画刷。
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 #include <Windows.h> 2 3LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 4 5int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 6 PSTR szCmdLine, int iCmdShow) 7{ 8 9 TCHAR szAppName[] = TEXT("Hello"); 10 WNDCLASS wndclass; 11 wndclass.style = CS_HREDRAW | CS_VREDRAW; 12 wndclass.lpfnWndProc = WndProc; 13 wndclass.cbClsExtra = 0; 14 wndclass.cbWndExtra = 0; 15 wndclass.hInstance = hInstance; 16 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 17 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 18 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 19 wndclass.lpszMenuName = NULL; 20 wndclass.lpszClassName = szAppName; 2122if (!RegisterClass(&wndclass)) 23 { 24 MessageBox(NULL, TEXT("error"), szAppName, MB_ICONERROR); 25return0; 26 } 2728 HWND hwnd = CreateWindow(szAppName, 29 TEXT("Hello"), 30 WS_OVERLAPPEDWINDOW, 31 CW_USEDEFAULT, CW_USEDEFAULT, 32 CW_USEDEFAULT, CW_USEDEFAULT, 33 NULL, 34 NULL, 35 hInstance, 36 NULL); 3738 ShowWindow(hwnd, iCmdShow); 39 UpdateWindow(hwnd); 4041 MSG msg; 42while (GetMessage(&msg, NULL, 0, 0)) 43 { 44 TranslateMessage(&msg); 45 DispatchMessage(&msg); 46 } 47return msg.wParam; 48} 4950LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 51{ 52 HDC hdc; 53 PAINTSTRUCT ps; 54staticint cxClient = 0, cyClient = 0; 55static HBRUSH hBrush; 56switch (msg) 57 { 58case WM_CREATE: 59return0; 60case WM_SIZE: 61 cxClient = LOWORD(lParam); 62 cyClient = HIWORD(lParam); 63return0; 64case WM_PAINT: 65 hdc = BeginPaint(hwnd, &ps); 66 hBrush = CreateSolidBrush(0x0000ff00); 67 SelectObject(hdc, hBrush); 68 RoundRect(hdc, cxClient / 4, cyClient / 4, 3 * cxClient / 4, 3 * cyClient / 4, cxClient / 4, cyClient / 4); 69 DeleteObject(hBrush); 70 EndPaint(hwnd, &ps); 71return0; 72case WM_LBUTTONDOWN: 73return0; 74case WM_DESTROY: 75 PostQuitMessage(0); 76return0; 77 } 78return DefWindowProc(hwnd, msg, wParam, lParam); 79 }
注意到也使用了SelectObject这个函数,此时可以把GDI对象关联到设备。
一个程序可以创建6个GDI对象,分别是画笔,画刷,位图,区域,字体和调色板。
6.还原GDI对象。
当使用了一种新的GDI对象后,希望还原原有的GDI环境,应该如何做呢?
SelectObject返回值是旧的GDI对象,因此可以设置新GDI对象的时候将旧的GDI对象记录下来。
HPen hOldPen = (HPen)SelectObject(hdc, hPen);
最后删除新GDI环境之前,再把旧的GDI对象选入环境。
SelectObject(hdc, hOldPen);
GDI+
GDI+用一个“无状态模型”取代了GDI种把选中项目放到设备环境(DC)对象上的“状态模型”,
在GDI+种的每一个绘图操作都是相互独立的。图形对象(Graphics object)是绘图操作种唯一保留的对象。
1.使用GDI+的方法。
1)头文件引入#include <gdiplus.h>。
2)项目附加依赖项gdiplus.lib。
3)在程序开始时初始化GDI+环境。
ULONG_PTR uToken = 0;
GdiplusStartupInput gdiplusStartupInput;
GdiplusStartup(&uToken, &gdiplusStartupInput, NULL);
4)在程序结束时释放GDI+环境。
GdiplusShutdown(uToken);
2.GDI和GDI+的绘制对比。
有了以上的准备,直接来看画一条线的方法:
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 #include <Windows.h> 2 #include <gdiplus.h> 3 4usingnamespace Gdiplus; 5 6LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); 7 8int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, 9 PSTR szCmdLine, int iCmdShow) 10{ 1112 ULONG_PTR uToken = 0; 13 GdiplusStartupInput gdiplusStartupInput; 14 GdiplusStartup(&uToken, &gdiplusStartupInput, NULL); 1516 TCHAR szAppName[] = TEXT("Hello"); 17 WNDCLASS wndclass; 18 wndclass.style = CS_HREDRAW | CS_VREDRAW; 19 wndclass.lpfnWndProc = WndProc; 20 wndclass.cbClsExtra = 0; 21 wndclass.cbWndExtra = 0; 22 wndclass.hInstance = hInstance; 23 wndclass.hIcon = LoadIcon(NULL, IDI_APPLICATION); 24 wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); 25 wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); 26 wndclass.lpszMenuName = NULL; 27 wndclass.lpszClassName = szAppName; 2829if (!RegisterClass(&wndclass)) 30 { 31 MessageBox(NULL, TEXT("error"), szAppName, MB_ICONERROR); 32return0; 33 } 3435 HWND hwnd = CreateWindow(szAppName, 36 TEXT("Hello"), 37 WS_OVERLAPPEDWINDOW, 38 CW_USEDEFAULT, CW_USEDEFAULT, 39 CW_USEDEFAULT, CW_USEDEFAULT, 40 NULL, 41 NULL, 42 hInstance, 43 NULL); 4445 ShowWindow(hwnd, iCmdShow); 46 UpdateWindow(hwnd); 4748 MSG msg; 49while (GetMessage(&msg, NULL, 0, 0)) 50 { 51 TranslateMessage(&msg); 52 DispatchMessage(&msg); 53 } 5455 GdiplusShutdown(uToken); 56return msg.wParam; 57} 5859LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) 60{ 61 HDC hdc; 62 PAINTSTRUCT ps; 63staticint cxClient = 0, cyClient = 0; 6465switch (msg) 66 { 67case WM_CREATE: 68return0; 69case WM_SIZE: 70 cxClient = LOWORD(lParam); 71 cyClient = HIWORD(lParam); 72return0; 73case WM_PAINT: 74 { 75 hdc = BeginPaint(hwnd, &ps); 76 Graphics graphics(hdc); 77 Pen greenPen(Color(255, 0, 255, 0)); 78 graphics.DrawLine(&greenPen, 0, cyClient / 2, cxClient, cyClient / 2); 7980 EndPaint(hwnd, &ps); 81 } 82return0; 83case WM_LBUTTONDOWN: 84return0; 85case WM_DESTROY: 86 PostQuitMessage(0); 87return0; 88 } 899091return DefWindowProc(hwnd, msg, wParam, lParam); 92 }
Graphics graphics(hdc);
Pen greenPen(Color(255, 0, 255, 0));
graphics.DrawLine(&greenPen, 0, cyClient / 2, cxClient, cyClient / 2);
无需再像GDI一样,将画笔选入设备环境,而是直接用Graphics对象的对应函数,画笔也是函数的一个参数。
为了让代码更清晰,把画线、画矩形单独写成一个函数,传入一个hdc。
以下是使用GDI绘制和使用GDI+绘制的各种对比。
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 void paintLine(HDC hdc) 2 { 3 // GDI 4 HPEN hPen = CreatePen(PS_SOLID, 1, 0x0000ff00); 5 HPEN hOldPen = (HPEN)SelectObject(hdc, hPen); 6 MoveToEx(hdc, 0, cyClient / 2, NULL); 7 LineTo(hdc, cxClient, cyClient / 2); 8 DeleteObject(hPen); 9 SelectObject(hdc, hOldPen); 1011// GDI+12 Graphics graphics(hdc); 13 Pen greenPen(Color(255, 0, 255, 0)); 14 graphics.DrawLine(&greenPen, 0, cyClient / 2, cxClient, cyClient / 2); 15 }
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 void paintRec(HDC hdc) 2 { 3 // GDI 4 HBRUSH hBrush = CreateSolidBrush(0x0000ff00); 5 HBRUSH hOldBrush = (HBRUSH)SelectObject(hdc, hBrush); 6 7 Rectangle(hdc, cxClient / 8, cyClient / 8, 7 * cxClient / 8, 7 * cyClient / 8); 8 9 DeleteObject(hBrush); 10 SelectObject(hdc, hOldBrush); 1112// GDI+13 Graphics graphics(hdc); 14 Pen blackPen(Color(255, 0, 0, 0)); 15 SolidBrush greenBrush(Color(255, 0, 255, 0)); 16 graphics.DrawRectangle(&blackPen, Rect(cxClient / 8, cyClient / 8, 6 * cxClient / 8, 6 * cyClient / 8)); 17 graphics.FillRectangle(&greenBrush, Rect(cxClient / 8 + 1, cyClient / 8 + 1, 6 * cxClient / 8 - 1, 6 * cyClient / 8 - 1)); 18 }
GDI+绘制矩形的后两个参数是高度、宽度和GDI的决定坐标有区别。
另外GDI+填充用的是Fill系列的函数,想要达到和GDI一样的效果需要考虑边框的一个像素。
3.GDI+的渐变画刷。
GDI+实现了一个渐变画刷,这在GDI是没有的。
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 Graphics graphics(hdc); 2 LinearGradientBrush linearBrush(Point(cxClient / 8, cyClient / 8), Point(7 * cxClient / 8, 7 * cyClient / 8), Color(255, 0, 0, 255), Color(255, 255, 0, 0)); 3 graphics.FillRectangle(&linearBrush, Rect(cxClient / 8 + 1, cyClient / 8 + 1, 6 * cxClient / 8 - 1, 6 * cyClient / 8 - 1));
内存DC
当需要绘制的图形、位图过多时,屏幕可能出现闪烁问题。
原因是WM_PAINT消息中每次绘制都是直接往目标DC绘制,有大量操作。
可以首先创建一个内存DC,一个位图选入此内存DC,所需绘制的内容先在新建的内存DC中绘制,再最后一次拷贝到目标DC。
此操作可称为双缓冲。
![技术分享图片](/img/jia.gif)
![技术分享图片](/img/jian.gif)
1 HDC hMemDc = CreateCompatibleDC(hdc); 2 HBITMAP hbitmap = CreateCompatibleBitmap(hdc, cxClient, cyClient); 3 HBITMAP hOldBitmap = (HBITMAP)SelectObject(hMemDc, hbitmap); 4 5// paint code 6paintLine(hMemDc); 7paintRec(hMemDc); 8paintEllipse(hMemDc); 9paintRoundRec(hMemDc); 1011 BitBlt(hdc, 0, 0, cxClient, cyClient, hMemDc, 0, 0, SRCCOPY); 12SelectObject(hMemDc, hOldBitmap); 13DeleteObject(hbitmap); 14 DeleteDC(hMemDc);
原文:https://www.cnblogs.com/yao2yaoblog/p/13208639.html
内容总结
以上是互联网集市为您收集整理的windows GDI和GDI+对比小结全部内容,希望文章能够帮你解决windows GDI和GDI+对比小结所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。