前言:
想在窗口上绘制出各种各样的图形,Windows给我们提供了大量的API函数,这些绘图函数种类很多,基本上能满足我们的绘图需求。要绘制出漂亮的图形,这时需要用到画笔和画刷了,简单来说,画笔是用来画线和边框的,那画刷就是用来填充那些封闭图形的。画笔能够控制线条的颜色、样式、大小等,画刷能够控制填充的类型、颜色、方式等。下面介绍画笔画刷的创建和使用,还有各种图形的绘制。颜色都用RGB进行设置。矩形、椭圆、弓形、扇形、多边形等这些是填充图形,都用当前的画笔画轮廓,用当前的画刷和多边形填充模式画填充。在绘制多条折线或多个多边形时,顶点数组定义时,需要注意:顶点是连续定义的,也按一笔画绘制。

在这里插入图片描述


一、画笔和画刷

画笔画刷的使用步骤:(两者使用一致)
1.创建画笔或画刷。
2.选取画笔或画刷(选入设备环境,记得保留先前画笔和画刷)(用SelectObject,此函数返回值为先前画笔画刷)。
3.使用绘图函数进行绘图。
4.删除自己所创建的画笔或画刷。(用DeleteObject)


画笔:

画笔的不同创建:

1.GetStockObject函数

GetStockObject 函数用于获得 Windows 预设的画笔、画刷、字体或者调色板的句柄。 (样式获取点击上面链接即可)

HGDIOBJ GetStockObject(  _In_  int fnObject);//指定待获取对象的类型

注意: 当样式为DC_BRUSH或DC_PEN时,需要调用 SetDCBrushColorSetDCPenColor 函数可以修改该值的颜色,将当前设备上下文环境(DC)的笔颜色设置为指定颜色值。

2.CreatePen函数

CreatePen是指定的样式、宽度和颜色创建画笔。返回画笔HPEN

HPEN CreatePen(int nPenStyle, int nWidth, COLORREF crColor);//样式、笔宽、颜色
Style 参数可选值:含义
PS_SOLID = 0实线
PS_DASH = 1段线; 要求笔宽<=1
PS_DOT = 2;点线; 要求笔宽<=1
PS_DASHDOT = 3线、点; 要求笔宽<=1
PS_DASHDOTDOT = 4线、点、点; 要求笔宽<=1
PS_NULL = 5;不可见
PS_INSIDEFRAME = 6实线; 但笔宽是向里扩展
3.CreatePenIndirect函数

CreatePenIndirect,根据指定的LOGPEN结构创建,这个结构与CreatePen函数的参数非常接近.

画笔使用实例:

HPEN hpen = CreatePen(PS_SOLID,0,RDB(255,0,0)); //创建 一条红色实线
HPEN oldhpen = SelectObject(hdc,hpen); // 画笔选入设备环境,并保留先前画笔
MoveToEx(hdc,0,0,NULL);  //画一条直线
LineTo(hdc,100,100);  
SelectObject(hdc,oldhpen); // 恢复先前画笔
DeleteObject(hpen); // 删除创建画笔hpen

画刷:

画刷的不同创建:

1. 实心画刷CreateSolidBrush函数
HBRUSH CreateSolidBrush(COLORREF clrref);// 参数为填充颜色RGB的值

CreateSolidBrush函数,该函数创建一个具有指定颜色的逻辑刷子。画笔可以随后被选为任何设备上下文的当前刷子。

2. 阴影画刷CreateHatchBrush函数
HBRUSH CreateHatchBrush(int fnStyle, COLORREF clrref);
                        // fnStyle:指定刷子的阴影样式
                        // cirref:指定用于阴影的刷子的前景色
样式说明
HS_BDIAGONAL表示45度向上,从左至右的阴影(/)
HS_CROSS水平和垂直交叉阴影(+++++)
HS_DIAGCROSS45度交叉阴影(XXXXX)
HS_FDIAGONAL45度向下,自左至右阴影(\\\)
HS_HORIZONTAL水平阴影(-----)
HS_VERTICAL垂直阴影
3. CreateBrushIndirect函数
HBRUSH CreateBrushlndirect(CONST LOGBRUSH *lplb);// LOGBRUSH结构体

CreateBrushIndirect,可以创建具有指定风格、颜色和模式的逻辑刷子。
LOGBRUSH结构体

画刷使用实例:

HBRUSH hbrush = CreateSolidBrush(RGB(0,255,0)); // 创建一个绿色实心画刷
HBRUSH oldhbrush = SelectObject(hdc,hbrush); // 选入设备环境,并保留先前画刷
Rectangle(hdc,100,100,200,200); // 绘制一个矩形
SelectObject(hdc,oldhbrush); // 恢复画刷
DeleteObject(hbrush); // 删除创建画刷 

二、绘图

1. 一个点的绘制

API函数:

绘制:

COLORREF SetPixel(
 HDC hdc, //DC句柄
 int X, //x坐标
 int Y, //y坐标
 COLORREF crColor ); // 点的颜色

获取:

 COLORREF GetPixel(
 HDC hdc,   //DC句柄
 int XPos,  //x坐标
 int nYPos ); //y坐标
// 返回指定坐标位置的点的颜色

2. 直线的绘制

API函数:
如果无MoveToEx,直线默认起点为原点(0,0);GetCurrentPositionEx函数能够获取当前位置。

BOOL MoveToEx(  // 移动当前位置
  HDC hdc,     // 句柄
  int X,     // 起点X坐标
  int Y,     // 起点Y坐标
  LPPOINT lpPoint );  // 一个指向POINT结构的指针,用来存放上一个点的位置,
                         若此参数为NULL,则不保存上一个点的位置。
BOOL LineTo(
  HDC hdc,    //  句柄
  int nXEnd,  //  终点X坐标
  int  YEnd   //  终点Y坐标
);

3. 折线的绘制

API函数:
PolylineTo 与Polyline类似, PolylineTo的不同就是:在绘制折线前,会将当前位置连一根线到折线的第一个顶点。
一条折线的绘制:

 BOOL Polyline( HDC hdc,             // DC句柄
                CONST POINT *lppt,   // 顶点的坐标数组
                int cPoints );       // 顶点的个数

多条折线的绘制:

 BOOL PolyPolyline( HDC hdc,   // 句柄
                    CONST POINT *lppt,   // 所有点的数组(按顺序)
                    CONST DWORD *lpdwPolyPoints ,// 每条顶点个数的数组
                    DWORD cCount );   // 折线的条数

4. 贝塞尔曲线的绘制

API函数:
4个点: 1和4是端点,2.3点是控制点
7个点: 1.4.7是端点,其余是控制点

BOOL PolyBezier(HDC hdc,           // 句柄
                CONST POINT *lppt, // 点数组,最少4个点
                DWORD cPoints );   // 点的数量

5. 矩形的绘制

API函数:
普通矩形绘制:

BOOL RoundRect( HDC hdc,
                int nLeftRect,    // 左上X坐标
                int nTopRect,     // 左上Y坐标
                int nRightRect,   // 右下X坐标
                int nBottomRect); // 右下Y坐标

圆角矩形绘制:
圆角的生成是由椭圆的弧调节的。

BOOL RoundRect( HDC hdc,
                int nLeftRect,   // 左上X坐标
                int nTopRect,    // 左上Y坐标
                int nRightRect,  // 右下X坐标
                int nBottomRect, // 右下Y坐标
                int nWidth,      // 生成圆角的椭圆的宽度
                int nHeight );   // 生成圆角的椭圆的高度

6. 椭圆和圆的绘制

API函数:
椭圆和圆由外切矩形控制。

BOOL Ellipse( HDC hdc,
              int nLeftRect,    // 外切矩形左上X坐标
              int nTopRect,     // 外切矩形左上Y坐标
              int nRightRect,   // 外切矩形右下X坐标
              int nBottomRect); // 外切矩形右下Y坐标

7. 圆弧的绘制

API函数:
Arc函数: 可以使用SetArcDirection函数,设置Arc函数切割方向,顺时针和逆时针。这里所说的切割半径坐标意思是说,此坐标与椭圆中点的连线为半径,两条半径之间形成弧。

 BOOL Arc( HDC hdc, 
           int nLeftRect,   // 外切矩形的坐标
           int nTopRect,    // 外切矩形的坐标
           int nRightRect,  // 外切矩形的坐标
           int nBottomRect, // 外切矩形的坐标
           int nXStartArc,  // 起始切割半径的X坐标
           int nYStartArc,  // 起始切割半径的Y坐标
           int nXEndArc,    // 终止切割半径的X坐标
           int nYEndArc );  // 终止切割半径的X坐标

AngleArc函数: 直线连弧绘制函数,需要注意的 ,会与当前位置连接起来。

BOOL AngleArc( HDC hdc,
               int X,          // 圆心的X坐标
               int Y,          // 圆心的Y坐标
               DWORD dwRadius,    // 圆的半径
               FLOAT eStartAngle, // 开始角度
               FLOAT eSweepAngle ); // 夹角

8. 弓形弦的绘制

API函数:
填充图形,弧的首尾相连形成弓形。

BOOL Chord( HDC hdc, 
            int nLeftRect,   // 外切矩形左上X坐标
            int nTopRect,    // 外切矩形左上Y坐标
            int nRightRect,  // 外切矩形右下X坐标
            int nBottomRect, // 外切矩形右下Y坐标
            int nXRadial1,   // 切割起始半径X坐标
            int nYRadial1,   // 切割起始半径Y坐标
            int nXRadial2,   // 切割终止半径X坐标
            int nYRadial2 ); // 切割终止半径Y坐标

9. 扇形饼的绘制

API函数:

 BOOL Pie( HDC hdc, 
           int nLeftRect,   // 外切矩形左上X坐标
           int nTopRect,    // 外切矩形左上Y坐标
           int nRightRect,  // 外切矩形右下X坐标
           int nBottomRect, // 外切矩形右下Y坐标
           int nXRadial1,   // 切割起始半径X坐标
           int nYRadial1,   // 切割起始半径Y坐标
           int nXRadial2,   // 切割终止半径X坐标
           int nYRadial2 ); // 切割终止半径Y坐标

10. 多边形的绘制

在多边形绘制这里会有用到多边形填充模式,填充模式一共有两种:ALTERANATE(交替式,默认)WINDING(螺旋式)。用SetPolyFillMode函数设置
API函数:
一个多边形的绘制:

 BOOL Polygon( HDC hdc,
               CONST POINT *lpPoints, // 多边形的顶点
               int nCount );          // 顶点的数量

多个多边形的绘制:
第二个参数中各多边形是连续定义的,每个多边形通过画一条从最后中一个顶点到第一个顶点的线段而自动闭合起来,每个顶点应被定义一次。

BOOL PolyPolygon( HDC hdc,
                  CONST POINT *lpPoints, // 顶点的POINT结构数组的指针
                  CONST INT *lpPolyCounts, //整数数组的指针,每个整数指定
                                //相应多边表的点数,每个整数必须大于等于2
                  int nCount); // 指定多边形的总个数

三、代码(绘制以上所有图形)

在这里插入图片描述

LRESULT CALLBACK WndProc(HWND hwnd, UINT Message, WPARAM wParam, LPARAM lParam) {
	PAINTSTRUCT ps;
	HDC hdc;
	HPEN hpen1, oldhpen, hpen2, hpen3, hpen4, hpen5,hpen;
	HBRUSH hbrush1, oldhbrush, hbrush2, hbrush3, hbrush4, hbrush5,hbrush6;
	static int xClient, yClient;
	static POINT apt[5] = { 90,50,110,10,130,50,150,10,180,50 };//5个点
	static POINT capt[] = { 200, 50, 230, 10, 260, 50, 290, 10, 310, 50,
					200, 100, 230, 60, 260, 100, 290, 60, 310, 100,
					200, 150, 230, 110, 260, 150, 290, 110, 310, 150 };
	static DWORD asz[] = { 5,5,5 };
	static POINT bapt[4] = { 350,50,350,80,370,50,450,10 };//4个点
	switch (Message)
	{
	case WM_SIZE:
	{
		xClient = LOWORD(lParam);
		yClient = HIWORD(lParam);
		break;
	}
	case WM_PAINT:
	{
		hdc = BeginPaint(hwnd, &ps);
		//还可以使用CreatePenIndirect创建画笔
		//画一个红色点
		SetPixel(hdc, 20, 50, RGB(255, 0, 0));

		//画一条直线
		hpen1 = CreatePen(PS_SOLID, 1, RGB(255, 0, 0));//实线
		oldhpen = (HPEN)SelectObject(hdc, hpen1);//选入画笔
		MoveToEx(hdc, 30, 50, NULL);
		LineTo(hdc, 70, 50);
		SelectObject(hdc, oldhpen);//恢复先前画笔
		DeleteObject(hpen1);//记得自创画笔一定删除

		//画一条5个点折线
		hpen2 = CreatePen(PS_DASH, 1, RGB(255, 255, 0));//段线
		oldhpen = (HPEN)SelectObject(hdc, hpen2);//选入画笔
		Polyline(hdc, apt, 5); //其后缀不带To,表示该函数不使用也不改变设备当前位置
		SelectObject(hdc, oldhpen);//恢复先前画笔
		DeleteObject(hpen2);//记得自创画笔一定删除

		//画3条折线
		hpen3 = CreatePen(PS_DASHDOT, 1, RGB(255, 0, 255));//线点
		SetBkColor(hdc, RGB(0, 0, 222));// 设置当前背景颜色
		oldhpen = (HPEN)SelectObject(hdc, hpen3);//选入画笔
		PolyPolyline(hdc, capt, asz, 3);
		SelectObject(hdc, oldhpen);//恢复先前画笔
		DeleteObject(hpen3);//记得自创画笔一定删除

		//画贝塞尔曲线(最少需要4个点)
		hpen4 = (HPEN)GetStockObject(BLACK_PEN);//获得Windows预设的画笔画刷
		oldhpen = (HPEN)SelectObject(hdc, hpen4);//选入画笔
		PolyBezier(hdc, bapt, 4);// 4个点: 1和4是端点, 2.3点是控制点
		                         // 7个点 : 1.4.7是端点, 其余是控制点
		SelectObject(hdc, oldhpen);//恢复先前画笔
		DeleteObject(hpen4);//记得自创画笔一定删除
		
		//画无边框矩形
		hbrush1 = CreateSolidBrush(RGB(0, 255, 0)); //绿色实心画刷
		hpen = CreatePen(PS_NULL, 1, 0);  //创建空画笔
		oldhpen=(HPEN)SelectObject(hdc, hpen);  //重点:填充图形的边框由当前画笔绘制
		oldhbrush=(HBRUSH)SelectObject(hdc, hbrush1);//选入环境句柄
		Rectangle(hdc, 10, 80, 70, 140);
		SelectObject(hdc, oldhpen);
		SelectObject(hdc, oldhbrush);
		DeleteObject(hbrush1);//删除画刷

		//圆角矩形
		SetBkColor(hdc, RGB(0, 0, 0));// 设置当前背景颜色
		hbrush2=CreateHatchBrush(HS_FDIAGONAL,RGB(255,255,0));//创建画刷
		oldhbrush = (HBRUSH)SelectObject(hdc, hbrush2);//选入设备环境
		RoundRect(hdc, 90, 80, 150, 140,20,20);//画图
		SelectObject(hdc,oldhbrush);//恢复先前画刷
		DeleteObject(hbrush2);//删除画刷

		//椭圆
		SetBkColor(hdc, RGB(222, 0, 0));// 设置当前背景颜色
		hbrush3=CreateHatchBrush(HS_CROSS,RGB(255,255,0));
		oldhbrush = (HBRUSH)SelectObject(hdc, hbrush3);
		Ellipse(hdc, 10, 160, 70, 200);
		SelectObject(hdc,oldhbrush);
		DeleteObject(hbrush3);

		//普通弧
		SetDCPenColor(hdc, RGB(255, 0, 255));  //设置句柄颜色
		hpen5 = (HPEN)GetStockObject(DC_PEN);
		oldhpen = (HPEN)SelectObject(hdc, hpen5);
		Arc(hdc, 90, 160, 150, 200, 90, 180, 150, 170);
		SelectObject(hdc, oldhpen);
		DeleteObject(hpen5);
		//圆弧
		MoveToEx(hdc, 190, 200, NULL);
		AngleArc(hdc, 190, 200,30,10,90);  //终点会与当前位置连接起来
		
		//弓形、弦
		hbrush4 = CreateSolidBrush(RGB(155, 155, 155));
		oldhbrush = (HBRUSH)SelectObject(hdc, hbrush4);
		Chord(hdc, 240, 160, 300, 240, 270, 180, 290, 230);
		SelectObject(hdc, oldhbrush);
		DeleteObject(hbrush4);

		//扇形
		SetBkColor(hdc, RGB(35, 55, 111));// 设置当前背景颜色
		hbrush5 = CreateHatchBrush(HS_HORIZONTAL, RGB(0, 255, 0));
		oldhbrush = (HBRUSH)SelectObject(hdc, hbrush5);
		Pie(hdc, 330, 160, 370, 220, 333, 26, 370, 220);
		SelectObject(hdc, oldhbrush);
		DeleteObject(hbrush5);

		//绘制多边形,
		POINT dot[5]{100,300,200,300,125,350,150,250,175,350};//按笔画顺序绘制5个点
		SetPolyFillMode(hdc, ALTERNATE);//设置填充模式
		hbrush6 = CreateSolidBrush(RGB(0, 255, 0)); //绿色实心画刷
		oldhbrush = (HBRUSH)SelectObject(hdc, hbrush6);
		Polygon(hdc, dot, 5);//绘制多边形
		SelectObject(hdc, oldhbrush);
		DeleteObject(hbrush6);



		EndPaint(hwnd, &ps);
		break;
	}
	case WM_DESTROY: 
	{
		PostQuitMessage(0);
		break;
	}
	default:
		return DefWindowProc(hwnd, Message, wParam, lParam);


	}
	return 0;
}

留言:
我妈今天早上六点的样子就坐车出去了,当时还没睡醒,模模糊糊的,我妈是趁着我们放假在家,回来看看我们,她说她很想我们了。妈在前几天就跟我说,你车票买好、怎么坐车去车站、你衣服鞋子什么的自己整理好、自己在家去买菜吃、千万不能饿肚子啊,每天早点睡、不要玩手机到太晚,有时间就多出去走走,我想说有妈是天底下最幸福的事了。妈在家时,我真的是每天使劲玩,等着吃饭就好了,妈这出去了,心里总感觉少了什么,有点小不舒服,哈哈哈,可能又要自己动手煮饭了吧。以前小时候不怎么懂事,在家经常让我妈担心,有点后悔,现在我只希望我妈身体健健康康的、平安就好。当然,我爸也是一样,为我们的生活和成长,付出了他的全部。父爱同母爱一样的无私,他不求回报;父爱是一种默默无闻,寓于无形之中的一种感情,只有用心的人才能体会。在父母的眼中,孩子常是自我的一部分,子女是他理想自我再来一次的机会。我现在能做的就是让自己成为一个他们自豪的人!

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐