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

跟前面的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创建一个模式画刷即可。

  • 文本输出

这个在前面已经讨论过了,请参考【Windows编程】系列第三篇:文本字符输出一文。

  • 绘图属性

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

画笔位置:在画线条时,会从画笔所在的位置开始画,画笔位置可以用MoveToEx函数来设置。

画笔:绘图时会采用当前环境中的画笔进行绘制,如果显示不创建,将会用系统默认的画笔。

背景:某些GDI会有透明和不透明的设置。

背景颜色:比如文本输出的间隙颜色。

绘制模式:比如划线是可以设置实线、虚线等,填充时可能有不同的填充绘制模式。

下面我们通过一个完整的实例,来演示上面这些常见函数的具体运用以及实际使用效果。

#include <windows.h>

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)技术大牛做朋友,在线交流编程经验,获取编程基础知识,解决编程问题。程序员互动联盟,开发人员自己的家。

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

【Windows编程】系列第五篇:GDI图形绘制的更多相关文章

  1. Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) JAVA日志的前世今生 .NET MVC采用SignalR更新在线用户数 C#多线程编程系列(五)- 使用任务并行库 C#多线程编程系列(三)- 线程同步 C#多线程编程系列(二)- 线程基础 C#多线程编程系列(一)- 简介

    Python GUI之tkinter窗口视窗教程大集合(看这篇就够了) 一.前言 由于本篇文章较长,所以下面给出内容目录方便跳转阅读,当然也可以用博客页面最右侧的文章目录导航栏进行跳转查阅. 一.前言 ...

  2. C#网络编程系列文章(五)之Socket实现异步UDPserver

    原创性声明 本文作者:小竹zz 本文地址http://blog.csdn.net/zhujunxxxxx/article/details/44258719 转载请注明出处 文章系列文件夹 C#网络编程 ...

  3. 前端工程师技能之photoshop巧用系列第五篇——雪碧图

    × 目录 [1]定义 [2]应用场景 [3]合并[4]实现[5]维护 前面的话 前面已经介绍过,描述性图片最终要合并为雪碧图.本文是photoshop巧用系列第五篇——雪碧图 定义 css雪碧图(sp ...

  4. C#中的GDI+图形绘制方法

    GDI+图形绘制方法 1.首先对于绘制图形,必须的先将命名空间导入:using System.Drawing.Drawing2D; 2.然后在一个事件中写入程序 首先先将Graphics这个对象实例化 ...

  5. 学习ASP.NET Core Razor 编程系列十五——文件上传功能(三)

    学习ASP.NET Core Razor 编程系列目录 学习ASP.NET Core Razor 编程系列一 学习ASP.NET Core Razor 编程系列二——添加一个实体 学习ASP.NET ...

  6. EnjoyingSoft之Mule ESB开发教程系列第五篇:控制消息的流向-数据路由

    目录 1. 使用场景 2. 基于消息头的路由 2.1 使用JSON提交订单的消息 2.2 使用XML提交订单的消息 2.3 使用Choice组件判断订单格式 3. 基于消息内容的路由 4. 其他控制流 ...

  7. C#多线程编程系列(五)- 使用任务并行库

    目录 1.1 简介 1.2 创建任务 1.3 使用任务执行基本的操作 1.4 组合任务 1.5 将APM模式转换为任务 1.6 将EAP模式转换为任务 1.7 实现取消选项 1.8 处理任务中的异常 ...

  8. 走进windows编程的世界-----入门篇

    1   Windows编程基础 1.1Win32应用程序基本类型 1)  控制台程序 不须要完好的windows窗体,能够使用DOS窗体方式显示 2)  Win32窗体程序 包括窗体的程序,能够通过窗 ...

  9. 【opencv系列04】OpenCV4.X图形绘制

    一. 基本图形绘制 1. 基本函数与参数 cv2.line(): 线 cv2.circle(): 圆 cv2.rectangle(): 矩形 cv2.ellipse(): 椭圆 cv2.putText ...

随机推荐

  1. clr enabled Server Configuration Option

    在SQL Server中启用CLR,可以执行下面SQL语句: EXEC sp_configure 'clr enabled'; '; RECONFIGURE; Source Code

  2. 利用SHELL脚本实现文件完整性检测程序(1.2版更新)

    一..开发背景 因时势所逼,需要对服务器的文件系统实行监控.虽然linux下有不少入侵检测和防窜改系统,但都比较麻烦,用起来也不是很称手.自己琢磨着也不需要什么多复杂的功能,写个脚本应该就可以满足基本 ...

  3. onclick标签变成小手状

    style=“cursor: pointer;”

  4. eclipse中怎么添加Hibernate tools

    最近在学习Hibernate框架,但是用eclipse的时候发现自己安装的过程不是很顺利,因此记下来,供自己和别人参考. Hibernate Tools是由JBoss推出的一个Eclipse集成开发工 ...

  5. PHP运算符

    运算符 PHP运算符可以根据操作数的个数分为一元运算符.二元运算符.三元运算符.一元运算符例如!(取反运算符)或++(加一运算符),PHP支持的大多数运算符都是这种二元运算符,例如+.-.*./等算数 ...

  6. 从零开始学 Java - Windows 下安装 Eclipse

    三观是什么鬼 当我们在讨论「三观一致」的时候是在讨论些什么? 我认为这个世界上本没有「三观」这一说法,说的人多了,也就有了「三观」这个词,当我们讨论「三观一致」其实并不是真的在说世界观.价值观.人生观 ...

  7. Spring(一)

    一. spring是什么? 我们知道struts 是 web 框架 (jsp/action/actionfrom).hibernate 是 orm框架,处于持久层. spring 是容器框架,用于配置 ...

  8. CSS背景图拉伸不变形

    在线效果体验:http://hovertree.com/texiao/mobile/3.htm 请使用手机浏览器查看. css代码: .bg{ background:url(http://hovert ...

  9. 使用gulp+browser-sync搭建前端项目自动化以及自动刷新

    前段时间使用了gulp+browser-sync才发现这个东西真的很好用. 准备工作:(1).安装nodejs.gulp是基于nodejs使用的,所以先安装nodejs,https://nodejs. ...

  10. 【高级功能】使用canvas元素(第一部分)

    1. 开始使用 canvas 元素 canvas 元素非常简单,这是指它所有的功能都体现在一个JavaScript对象上,因此该元素本身只有两个属性:width 和 height. canvas 元素 ...