您的当前位置:首页正文

【Windows编程】系列第五篇:GDI图形绘制

2023-03-18 来源:汇智旅游网
【Windows编程】系列第五篇:GDI图形绘制

上两篇我们学习了以及,知道如何⽤常见Win32输出⽂本字符串,这⼀篇我们来学习Windows编程中另⼀个⾮常重要的部分GDI图形绘图。Windows的GDI函数包含数百个API可供我们使⽤,本篇把最常⽤的GDI绘图做⼀个讲解。GDI可以绘制点、直线曲线、填充封闭区域、位图以及⽂本,其中⽂本部分已经在上⼀篇中将了,请参考。

跟前⾯的GDI对象⼀样,本篇的这些绘图函数也必须要设备上下⽂句柄(HDC)作为函数参数,从前⽂我们知道,HDC可以在处理WM_PAINT的时候⽤BeginPaint函数获取,也可以从GetDC、GetWindowDC拿到。

既然是画图,就少不了颜⾊的描述,Windows中的颜⾊有⼏种表⽰,其中COLORREF在GDI绘制中⽤的最多,它实际上是⼀个⽆符号32为整型。其中红、绿、蓝各占⼀个字节,最⾼字节不使⽤,如下图所⽰:该值可以⽤Windows提供的RGB宏来⽣成,Windows中RGB的定义为:

#define RGB(r,g,b) ((COLORREF)(((BYTE)(r)|((WORD)((BYTE)(g))<<8))|(((DWORD)(BYTE)(b))<<16)))

除此之外,Windows还有结构体RGBQUAD也表⽰颜⾊,这种⼀般⽤于位图结构信息中。

画像素点

Windows提供了SetPixel和GetPixel函数来设定和获取像素点的颜⾊。函数原型为:

COLORREF SetPixel(HDC hdc, int X, int Y, COLORREF crColor);COLORREF GetPixel(HDC hdc, int nXPos, int nYPos);

该函数并不常使⽤。

画笔画刷

在图形绘制之前,可以创建画笔给后续的画图使⽤,创建画笔的API函数为:

HPEN CreatePen(int fnPenStyle, int nWidth, COLORREF crColor);HBRUSH CreateSolidBrush(COLORREF crColor);HBRUSH CreatePatternBrush(HBITMAP hbmp);

HBRUSH CreateHatchBrush(int fnStyle, COLORREF clrref);

它可以指定画笔风格,宽度和颜⾊。风格可以是实线、虚线、点虚线等,具体参考MSDN说明的各种类型。

画线条

Windows提供的画线条函数有⼗⼏个,常⽤的直线绘制为LineTo,多条线段⼀般⽤Polyline、PolylineTo、PolyPolyine等,曲线可以画椭圆、椭圆弧、贝塞尔样条曲线。这些函数的原型请参考MSDN,后⾯我们将⽤实例来演⽰这些函数的⽤法。

封闭区域填充

Windows的绘图如果是⼀个封闭区,则内部是可以填充的,当然如果你不显⽰填充,系统会⽤默认颜⾊来填,⽐如窗⼝背景⾊。我们也可以在绘制封闭图形之前创建画刷,如果把创建的画刷选⼊设备环境中,系统将⽤画刷填充内部区。常见的会封闭的绘图API函数有画直⾓矩形Rectangle、圆⾓矩形RoundRect、椭圆Ellipse、扇形图Pie以及弦割图Chord。

位图输出

Windows关于位图的输出内容很多,包括设备相关和设备⽆关位图、以及位块转移、透明、缩放等等,本⽂仅针对位图画刷进⾏实例演⽰,其他内容将来可单独写⼀篇介绍。⽤位图做画刷时先要使⽤LoadImage函数加载位图⽂件,然后⽤CreatePatternBrush创建⼀个模式画刷即可。

⽂本输出

这个在前⾯已经讨论过了,请参考⼀⽂。

绘图属性

在绘制图形时,环境设备有5个属性会影响⼤多数绘图:

画笔位置:在画线条时,会从画笔所在的位置开始画,画笔位置可以⽤MoveToEx函数来设置。画笔:绘图时会采⽤当前环境中的画笔进⾏绘制,如果显⽰不创建,将会⽤系统默认的画笔。背景:某些GDI会有透明和不透明的设置。背景颜⾊:⽐如⽂本输出的间隙颜⾊。

绘制模式:⽐如划线是可以设置实线、虚线等,填充时可能有不同的填充绘制模式。下⾯我们通过⼀个完整的实例,来演⽰上⾯这些常见函数的具体运⽤以及实际使⽤效果。

#include

static TCHAR szAppName[] = TEXT(\"GDI Test\");

static LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow){

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(\"This program requires Windows NT!\"), szAppName, MB_ICONERROR); return 0; }

hWnd = CreateWindow(szAppName, // window class name szAppName, // window caption

WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position 400, // initial x size 300, // initial y size

NULL, // parent window handle NULL, // window menu handle

hInstance, // program instance handle NULL); // creation parameters

ShowWindow(hWnd, iCmdShow); UpdateWindow(hWnd);

while (GetMessage(&msg, NULL, 0, 0)) {

TranslateMessage(&msg); DispatchMessage(&msg); }

return msg.wParam;}

//绘制指定属性的直线

static void DrawLine(HDC hDC, int x0, int y0, int x1, int y1, int style, int width, COLORREF color){

HPEN hPen = CreatePen(style, width, color);

HPEN hOldPen = (HPEN)SelectObject(hDC, hPen); MoveToEx(hDC, x0, y0, NULL); LineTo(hDC, x1, y1); SelectObject(hDC, hOldPen); DeleteObject(hPen);}

//绘制实⼼圆

static void DrawCircle(HDC hDC, int x, int y, int len, COLORREF color){

HBRUSH hBrush = CreateSolidBrush(color);

HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush); HPEN hPen = CreatePen(PS_SOLID, 1, color); HPEN hOldPen = (HPEN)SelectObject(hDC, hPen); Ellipse(hDC, x-len/2, y-len/2, x+len/2, y+len/2); SelectObject(hDC, hOldBrush); DeleteObject(hPen);

SelectObject(hDC, hOldPen); DeleteObject(hOldBrush);}

//绘制填充矩形

static void DrawRect(HDC hDC, int left, int top, int width, int height, int style, COLORREF color){

HBRUSH hBrush = CreateHatchBrush(style, color);

HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush); Rectangle(hDC, left, top, left+width, top+height);

SelectObject(hDC, hOldBrush); DeleteObject(hOldBrush);}

//绘制位图填充矩形

static void DrawBmpRect(HDC hDC, int left, int top, int width, int height, LPCTSTR file){

HBITMAP hBitmap = (HBITMAP)LoadImage(NULL, file, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION); HBRUSH hBrush = CreatePatternBrush(hBitmap);

HBRUSH hOldBrush = (HBRUSH)SelectObject(hDC, hBrush); Rectangle(hDC, left, top, left+width, top+height); SelectObject(hDC, hOldBrush); DeleteObject(hOldBrush); DeleteObject(hBitmap);}

static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam){

HDC hDC; PAINTSTRUCT ps; switch (message) {

case WM_CREATE: return 0;

case WM_PAINT: {

hDC = BeginPaint(hWnd, &ps); for (int i=10; i<50; i+=4) {

SetPixel(hDC, i, 10, RGB(0, 0, 0)); //绘制像素点 }

//绘制不同模式的直线

DrawLine(hDC, 120, 30, 200, 30, PS_SOLID, 2, RGB(0,0,0)); DrawLine(hDC, 120, 50, 200, 50, PS_DASH, 1, RGB(100,0,200));

DrawLine(hDC, 120, 70, 200, 70, PS_DASHDOT, 1, RGB(100,250,100)); //绘制弧线、弦割线、饼图 Arc(hDC, 10, 30, 40, 50, 40, 30, 10, 40); Chord(hDC, 10, 60, 40, 80, 40, 60, 10, 70); Pie(hDC, 10, 90, 40, 110, 40, 90, 10, 100); POINT pt[4] = {{90,130},{60,40},{140,150},{160,80}}; //绘制椭圆、矩形

Ellipse(hDC,pt[0].x, pt[0].y, pt[1].x, pt[1].y); Rectangle(hDC, pt[2].x, pt[2].y, pt[3].x, pt[3].y);

//绘制贝塞尔曲线 PolyBezier(hDC, pt, 4);

//标出贝塞尔曲线的四个锚点

DrawCircle(hDC, pt[0].x, pt[0].y, 8, RGB(0,255,0)); DrawCircle(hDC, pt[1].x, pt[1].y, 8, RGB(0,0,255)); DrawCircle(hDC, pt[2].x, pt[2].y, 8, RGB(0,0,0)); DrawCircle(hDC, pt[3].x, pt[3].y, 8, RGB(255,0,0)); //绘制圆

DrawCircle(hDC, 100, 180, 60, RGB(0, 250, 250)); //绘制不同填充模式的矩形

DrawRect(hDC, 220, 20, 60, 40, HS_BDIAGONAL, RGB(255,0,0)); DrawRect(hDC, 220, 80, 60, 40, HS_CROSS, RGB(0,255,0));

DrawRect(hDC, 290, 20, 60, 40, HS_DIAGCROSS, RGB(0,0,255)); DrawRect(hDC, 290, 80, 60, 40, HS_VERTICAL, RGB(0,0,0)); //绘制位图

DrawBmpRect(hDC, 180, 140, 180, 100, TEXT(\"chenggong.bmp\")); //绘制⽂本

TextOut(hDC, 20, 220, TEXT(\"GDI画图输出测试程序\"), 11); }

EndPaint(hWnd, &ps); return 0;

case WM_DESTROY:

PostQuitMessage(0); return 0 ; }

return DefWindowProc (hWnd, message, wParam, lParam);}

本实例运⾏结果如下图所⽰,图中可以看到线条不平滑,这是因为Win32的画图函数是没有抗锯齿功能的,图越⼩,锯齿越明显。可以使⽤微软提供的GDI+绘图函数,具有抗锯齿效果。

Windows的GDI基本绘制其实并不难掌握,只要仔细阅读MSDN上API的详细使⽤说明就⼀定能正确使⽤,但是在创建GDI对象并使⽤后,⼀定要记得释放。

更多经验交流可以加⼊Windows编程讨论QQ群:454398517。

关注微信公众平台:(coder_online),你可以第⼀时间,和(java/C/C++/Android/Windows/Linux)技术⼤⽜做朋友,在线交流编程经验,获取编程基础知识,解决编程问题。,开发⼈员⾃⼰的家。

转载请注明出处,谢谢合作!

因篇幅问题不能全部显示,请点此查看更多更全内容