GDI基础(1):绘制线条和图形
1、
绘制一个像素点:SetPixel()。
绘制直线:MoveTo(),LineTo()。
绘制多个首尾相连的线:Polyline()。
绘制矩形:FrameRect(),Rectangle(),FillRect() ,FillSolidRect()。
绘制一个四个角是弧形的矩形:RoundRect()。
绘制圆形或椭圆:Ellipse()。
绘制弧线:Arc(),ArcTo()。
绘制三角形或多边形:Polygon()。
绘制饼形图:Pie()。
对矩形或指定区域的像素颜色进行反转:InvertRect()、InvertRgn()。
以上函数如果没有参数用来指定的话则使用的是当前默认画笔和画刷,可以使用CDC::SelectObject()来改变当前画笔和画刷,而如果只是想改变画笔或画刷的颜色则使用SetDCPenColor()、SetDCBrushColor()即可。
Polyline(const POINT* lpPoints, int nCount)中的lpPoints是要连结的那些点的数组,nCount为点的个数。如果nCount为2的话其相当于MoveTo()和LineTo()绘制一条直线。
FrameRect()用来绘制一个矩形边框,边框颜色由其参数指定,矩形内部是透明的,相当于使用了透明画刷;
Rectangle()用来绘制带边框的矩形,边框颜色和类型使用当前DC默认画笔类型,矩形内部使用当前DC默认画刷,如果想要改变边框或画刷的颜色、类型,可以使用SelectObject()将指定画笔或画刷选入当前DC,也可以直接使用SetDCPenColor()、SetDCBrushColor()。
FillRect()用来绘制一块无边框的矩形,矩形内部使用指定画刷颜色或类型。
FillSolidRect()与FillRect类似,FillSolidRect只能使用固体色(COLORREF类型),但FillRect使用画刷,因此可以为矩形填充固体色、抖动色、阴影、位图或使用调色板,而且FillSolidRect通常比FillRect快。
以下为使用FrameRect、Rectangle、FillRect的对比:

Arc()与ArcTo()的区别在于,Arc函数只是绘出给定的弧线,不会对画笔位置产生影响;而ArcTo函数在工作时将会从画笔原来所在点(默认起始为0,0)开始绘制一条直线到弧线的开始点,绘画弧线完成后还会将画笔移动到弧线的终点,从而对画笔位置造成影响。下面是网上找的两个示例图:


2、
画笔CPen、画刷CBrush、字体CFont、位图CBitmap、调色板CPalette等都是GDI对象,通常在函数没有参数指定的情况下我们使用的是DC当前默认GDI对象,如在使用MoveTo/LineTo画线的时候线条的颜色是黑色实线,即当前DC默认画笔为黑色实线,使用Rectangle()画矩形的时候使用的是默认的白色画刷。我们可以使用CDC::SelectObject()来改变DC的默认GDI对象,该函数返回DC中被替换的GDI对象,我们应该保存这个旧的GDI对象,当我们不需要使用新的GDI对象的时候再使用CDC::SelectObject()将旧的GDI对象恢复到DC中。
还可以通过HGDIOBJ GetStockObject(int i)函数来获得系统标准的GDI对象,其参数可以为:NULL_BRUSH透明(空)画刷、SYSTEM_FONT系统字体、DEFAULT_PALETTE缺省调色板等。GetStockObject返回的类型为HGDIOBJ,所以在使用的时候还应该将其返回值强制转换为我们所使用的GDI句柄类型,如HBRUSH、HFONT、HPALETTE等。还可以使用各GDI类型的静态成员函数FromHandle()由这个GDI句柄获得其对象指针。比如CBrush::FromHandle()可以由画刷句柄获得画刷对象的指针,它是一个静态成员函数。同理,对于CPen、CFont、CBitmap、CPalette等GDI对象,甚至CDC和CWnd等也包含静态成员函数FromHandle()。实际上,MFC对各种包含内核对象的封装类都有FromHandle(HANDLE h)方法。
CDC类的成员函数GetSafeHdc(void)可以获得CDC对象的句柄。
下面是一个使用例子,它先将当前DC画刷设置为了系统透明画刷再使用Rectangle()来画矩形:
HBRUSH hNull_Brush = (HBRUSH)GetStockObject(NULL_BRUSH);
CBrush *pBrush = CBrush::FromHandle(hNull_Brush);
CBrush* pOldBrush = dc.SelectObject(pBrush); CRect rect(, , , );
dc.Rectangle(&rect); dc.SelectObject(pOldBrush);
pBrush->DeleteObject();
与前面的例子对比就可以看出效果:

3、
CPen是画笔类,用来在DC上完成绘制线条的任务,常用的构造函数:
CPen(Int style,int width ,COLORREF color);
style:画笔样式,可以为以下样式:
PS_SOLID 实线
PS_DASH 虚线,该值只有当画笔宽度等于1个设备单位或更小时才有效
PS_DOT 点线,该值只有当画笔宽度等于1个设备单位或更小时才有效
PS_DASHDOT 点和虚线交替,该值只有当画笔宽度等于1个设备单位或更小时才有效
PS_DASHDOTDOT 双点线和虚线交替,该值只有当画笔宽度等于1个设备单位或更小时才有效
PS_NULL 空画笔
PS_GEOMETRIC 几何画笔
.......
width:画笔宽度。
color:画笔颜色。
如果CPen在定义的时候没有被初始化,那么在使用之前应该调用其以下的初始化函数来进行初始化。
CreatePen()用指定的样式、宽度、颜色初始化画笔。
CreatePenIndirect()用结构LOGPEN 中指定的风格初始化画笔。
绘制连续曲线的例子:
void CMFC_testDlg::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值 if(nFlags == MK_LBUTTON)//鼠标左键按下标志
{
CClientDC dc(this);
CPen pen(PS_DOT, , RGB(,,));//创建一个虚线线条,宽度为1,红色的画笔对象
CPen* pOldPen = dc.SelectObject(&pen);//将画笔对象选入到设备描述表中 dc.MoveTo(m_ptOrigin);
dc.LineTo(point);
m_ptOrigin = point;//修改线段的起点 dc.SelectObject(pOldPen);//恢复设备描述表
pen.DeleteObject();
} CDialogEx::OnMouseMove(nFlags, point);
}

CDC::SetROP2(int nDrawMode)用来设置画笔绘画的模式,其参数可以为R2_NOTXORPEN、R2_NOT等绘图模式。R2_NOTXORPEN绘图模式就是先把画笔颜色与屏幕颜色异或,异或之后再取反最后得到一个颜色值显示在屏幕上,而这种做法就会产生一个效果:比如用画笔画了一条线,然后再用画笔在相同的位置画这条线就会擦除原来画的线。R2_NOT绘画模式同样有在同一个地方画两次相当于什么都没画的功能,不过R2_NOT绘画模式第一次画的时候显示颜色并不是你选定的画笔颜色,而是系统默认画笔颜色。
所以SetROP2()可以用来当做橡皮筋来使用。
4、
CBrush为画刷类,画刷通常用来填充一块区域,可以为普通固体色画刷,位图画刷,阴影线画刷等。常用的构造函数:
CBrush( COLORREF crColor ); //普通画刷
CBrush( int nIndex, COLORREF crColor ); //阴影线画刷
CBrush( CBitmap* pBitmap ); //位图画刷
crColor:画刷或阴影线的颜色
nIndex:阴影线的风格,有以下风格可选:
HS_HORIZONTAL 水平的阴影线
HS_VERTICAL 垂直的阴影线
HS_CROSS 水平和垂直方向以网格线作出阴影
HS_BDIAGONAL 45度的向下影线(从左到右)
HS_FDIAGONAL 45度的向上阴影线(从左到右)
HS_DIAGCROSS 45度的网格线阴影
同CPen一样,如果CBrush在定义的时候没有被初始化,那么在使用之前应该调用其以下的初始化函数来进行初始化:
CreateSolidBrush() 用指定的颜色初始化画刷。
CreateHatchBrush() 用指定的阴影线初始化画刷。
CreateBrushIndirect() 用结构LOGBRUSH中指定的风格、颜色和模式初始化画刷。
CreatePatternBrush() 用位图指定的模式初始化画刷。
CreateDIBPatternBrush() 用独立于设备的位图(DIB)初始化画刷。
CreateSysColorBrush() 创建一个使用系统缺省颜色的画刷。
使用阴影线画刷:
CPaintDC dc(this);
CRect rect(, , , );
CBrush brush(HS_HORIZONTAL, RGB(,,));
dc.FillRect(&rect, &brush);
CRect rect2(, , , );
CBrush brush2(HS_CROSS, RGB(,,));
dc.FillRect(&rect2, &brush2);
CRect rect3(, , , );
CBrush brush3(HS_BDIAGONAL, RGB(,,));
dc.FillRect(&rect3, &brush3);
brush.DeleteObject();

使用位图画刷:
//使用位图画刷来填充一块矩形区域
CClientDC dc(this); CBitmap bitmap;
bitmap.LoadBitmapW(IDB_BITMAP1);//初始化位图对象
CBrush brush(&bitmap);//构造位图画刷 CRect rect(1, 1, , );
dc.FillRect(&rect, &brush);
bimap.DeleteObject();

如果在绘图过程中要经常改变DC中的画刷或画笔得颜色,可以使用SetDCBrushColor()、SetDCPenColor()函数来改变DC的画刷或画笔的颜色,在使用这两个函数之前要先将系统画刷DC_BRUSH或画笔DC_PEN选到DC中去:
CPaintDC dc(this);
dc.SelectObject(GetStockObject(DC_BRUSH));
dc.SelectObject(GetStockObject(DC_PEN)); //画圆,边框设为蓝色,内部为红色
dc.SetDCPenColor(RGB(,,));
dc.SetDCBrushColor(RGB(,,));
dc.Pie(,,,,,,,); //画饼,边框为红色,内部为蓝色
dc.SetDCPenColor(RGB(,,));
dc.SetDCBrushColor(RGB(,,));
dc.Ellipse(, , , );

5、
CPen、CBrush、CBitmap、CFont等GID对象在使用结束后应该调用DeleteObject()函数用来释放相关资源,而且只有这样才能重新初始化使用。我觉得MFC中的GDI对象会在析构的时候自动调用DelectObject(),win32的话必须显示调用DelectObject()防止内存泄露,所以用完之后再delete是一个好习惯。关于CFont和CBitmap这两个GDI对象会在下面的文章中详解。
6、
Windows中显示是基于设备环境(DC)的,在使用GDI函数之前必须先获得窗口的DC。在Win32 SDK中绘图的话需要调用GetDC()(WM_PAINT消息响应代码块中为BeginPaint)获得指定窗口的DC,绘制结束后还要调用ReleaseDC()(EndPaint())来释放DC资源。MFC的设备环境类CDC封装了窗口的DC对象和绘图所需要的所有函数。CClientDC、CWindowDC、CPaintDC都是从CDC类派生而来,只要在初始化的时候传入窗口的指针那么就可以通过这些对象的方法来方便的对窗口进行绘制等操作,而且DC资源释放会在对象的析构函数中自动执行。还有一个CMetaFileDC类,它对图像的保存比像素更精确,因而往往在要求较高的场合下使用,例如AutoCAD的图形保存等。
CClientDC获得的是窗口客户区的DC,所以只能在客户区画图,其原点坐标为客户区左上角;
CWindowDC获得的是整个窗口的DC,包括标题栏、边框等,其原点坐标也是整个窗口的左上角;
CPaintDC只用在窗口重绘消息响应函数中;
GetDesktopWindow()函数可以获得桌面窗口的指针,所以想在当前屏幕上进行绘图操作可以类似这样:
CWindowDC dc(GetDesktopWindow());//获得与当前桌面窗口相关联的CWindowDC对象
dc.MoveTo(, );
dc.LineTo(, );
7、
可以调用GradientFill()函数来绘制一块渐变色的矩形区域或三角形区域,eg:
void CMFCApplication9Dlg::OnPaint()
{
CPaintDC dc(this); TRIVERTEX vertex[];
vertex[].x = ;
vertex[].y = ;
vertex[].Red = 0x0000;
vertex[].Green = 0x8000;
vertex[].Blue = 0x8000;
vertex[].Alpha = 0x0000; vertex[].x = ;
vertex[].y = ;
vertex[].Red = 0x0000;
vertex[].Green = 0xd000;
vertex[].Blue = 0xd000;
vertex[].Alpha = 0x0000; GRADIENT_RECT gRect;
gRect.UpperLeft = ;
gRect.LowerRight = ; dc.GradientFill(vertex, , &gRect, , GRADIENT_FILL_RECT_H);
}

以上绘制的是水平渐变方式的矩形,也可以修改GradientFill()的最后一个参数为GRADIENT_FILL_RECT_V来实现垂直渐变的效果,如下图:

下面为绘制一个渐变三角形的示例:
void CMFCApplication9Dlg::OnPaint()
{
CPaintDC dc(this); TRIVERTEX vertex[];
vertex[].x = ;
vertex[].y = ;
vertex[].Red = 0xff00;
vertex[].Green = 0x8000;
vertex[].Blue = 0x0000;
vertex[].Alpha = 0x0000; vertex[].x = ;
vertex[].y = ;
vertex[].Red = 0x9000;
vertex[].Green = 0x0000;
vertex[].Blue = 0x9000;
vertex[].Alpha = 0x0000; vertex[].x = ;
vertex[].y = ;
vertex[].Red = 0x9000;
vertex[].Green = 0x0000;
vertex[].Blue = 0x9000;
vertex[].Alpha = 0x0000; GRADIENT_TRIANGLE gTriangle;
gTriangle.Vertex1 = ;
gTriangle.Vertex2 = ;
gTriangle.Vertex3 = ; dc.GradientFill(vertex, , &gTriangle, , GRADIENT_FILL_TRIANGLE);
}

GDI基础(1):绘制线条和图形的更多相关文章
- C# winform如何清除由Graphics类绘制出来的所有线条或图形
在C#winform应用程序中,可以用GDI绘制出线条或图形. 1.在主窗体上绘制线条或图形 using (Graphics g = this.CreateGraphics()) { ...
- GDI+入门——带你走进Windows图形的世界
一.GDI+基础 1.GDI+简单介绍 GDI+是微软的新一代二维图形系统,它全然面向对象,要在Windows窗口中显示字体或绘制图形必需要使用GDI+.GDI+提供了多种画笔.画刷.图像等图形对象, ...
- GDI+基础(1)
转载:http://www.cnblogs.com/peterzb/archive/2009/07/19/1526555.html System.Drawing 命名空间提供了对 GDI+ 基本图形功 ...
- Python:matplotlib绘制线条图
线型图是学习matplotlib绘图的最基础案例.我们来看看具体过程: 下面我们将两条曲线绘制到一个图形里: 可以看到这种方式下,两个线条共用一个坐标轴,并且自动区分颜色. plot方法的核心是 ...
- RRDtool绘制lvs连接数图形
需求:用RRDtool绘制lvs的连接数图形 RRDtool是一个强大的绘图工具,作者是Tobias Oetiker. RRD全称Round Robin Database,轮转数据库,也是一个时间序列 ...
- Quartz2D复习(一)--- 基础知识 / 绘制线段圆弧 / 图片水印 / 截图
1.Quartz 2D是一个二维绘图引擎,同时支持ios和Mac系统: Quart2D的API是纯C语言的,API来自于Core Graphics框架: 2.Quartz 2D可以绘制图形(线段/三 ...
- Win32 GDI基础(笔记)
1.GDI名字的意义 GDI Graphic Device Interface,我说不清和GUI有什么区别.可能一种针对设备,一种针对用户而言吧,反正以后都说GDI,也就是Windows的图形编程. ...
- 使用html5 Canvas绘制线条(直线、折线等)
使用html5 Canvas绘制直线所需的CanvasRenderingContext2D对象的主要属性和方法(有"()"者为方法)如下: 属性或方法 基本描述 strokeSty ...
- [Swift通天遁地]八、媒体与动画-(5)使用开源类库绘制文字、图形、图像、图表、SVG(可缩放矢量图形)
★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★➤微信公众号:山青咏芝(shanqingyongzhi)➤博客园地址:山青咏芝(https://www.cnblogs. ...
随机推荐
- Springboot学习01- 配置文件加载优先顺序和本地配置加载
Springboot学习01-配置文件加载优先顺序和本地配置加载 1-项目内部配置文件加载优先顺序 spring boot 启动会扫描以下位置的application.properties或者appl ...
- selenium模拟事件处理
执行原理: 调用ActionChains的方法时不会立即执行,会将所有的操作按顺序存放在一个队列里,当调用perform()方法时,从队列中的事件会依次执行. 支持链式写法或者是分布写法. 鼠标键盘方 ...
- webpack.dev.conf.js
var utils = require('./utils')var webpack = require('webpack')var config = require('../config') // 一 ...
- openCV基础知识
openCV主体分为5个模块: CV图像处理函数和计算机视觉算法: ML机器学习库,包含许多聚类和数据分析函数: HighGUI图像和视频的输入输出: [分成三部分:硬件部分--摄像机;文件部分--载 ...
- jar导入本地maven库
最近在了解视频监控相关sdk,海康威视官方sdk要求自己手工将fas-data-sdk-1.0-SNAPSHOT.jar导入本地maven库,maven配置文件pom.xml配置如下 <?xml ...
- Git 安装和使用教程(更加详细)
转载至:https://www.cnblogs.com/smuxiaolei/p/7484678.html#undefined Git 安装和使用教程 git 提交 全部文件 git add . g ...
- 点评10款Github上最火爆的国产开源项目
衡量一个开源产品好不好,看看产品在Github的Star数量就知道了.由此可见,Github已经沦落为开源产品的“大众点评”了. 一个开源产品希望快速的被开发者知道.快速的获取反馈,放到Github上 ...
- DtCMS 在IIS7.0 下之伪静态
1)首先新建一个应用程序池,名称任意,比如:nettest,托管管道模式先暂时设置为集成模式,等下面的一系列设置完成之后再设置成经典模式: 2)部署好站点,并将此站点的应用程序池设置为nettest; ...
- VS2010正则批量替换set_和get_
批量替换set_: daohang.set_ChannelName(rowArray[0]["ChannelName"].ToString()); daohang.set_Chan ...
- 链接PDO
header('Content-type:text/html;Charset=utf-8'); /** * 实例化PDO对象 */ // 1, 设置相关的参数 // 1.1 确定数据源 $dbms = ...