/*第十五章 在窗口中绘图
主要内容:
1 Windows为窗口绘图提供的坐标系统
2 设置环境及其必要性
3 程序如何以及在窗口中绘图
4 如何定义鼠标消息的处理程序
5 如何定义自己的形状类
6 在窗口中绘制形状时如何对鼠标进行编程
7 如何让程序捕获鼠标15.1 窗口绘图的基础知识15.1.1 窗口客户区
由于可以使用鼠标来回拖动窗口,并且可以通过拖动其边框调整大小,因此窗口在屏幕上没有一个固定的位置,甚至没有一个固定的可视区,那么如何知道应当在屏幕上的什么地方绘图呢15.1.2 Windows图形设备界面
从直接的意义上来说,windows的最后一个限制是实际上没有把数据写入屏幕,所有到显示屏的输出都是图形,而不管它是直线,圆还是文本1 设置环境2 映射模式设备环境中的每种映射模式都有一个ID标识,其方式与标识windows消息时类似,映射模式
MM_TEXT  逻辑单位是一个设备像素,在窗口客户区中,x轴的正方向从左到右,y轴的正方向从上到下MM_LOENGLISH 逻辑单位是0.0.1英寸,x轴的正方向从左到右,y轴的正方向从客户区的顶部向上延伸MM_HIENGLISH 逻辑单位是0.001英寸,x轴和y轴的方向与MM_LOENGLISH相同
MM_LOMETRIC 逻辑单位是0.1毫米,x轴和y轴的方向与MM_LOENGLISH相同
MM_HIMETRIC 逻辑单位是0.01毫米,x轴和y轴的方向与MM_LOENGLISH相同MM_ISOTROPIC 逻辑单位是任意长度,但是在x轴和y轴上是相同的,x轴和y轴的方向与MM_LOENGLISH相同MM_ANISOTROPIC 这种模式似乎MM_ISOTROPIC,但是它允许x轴上逻辑单位的长度不同于y轴上逻辑单位的长度MM_TWIPS 逻辑单位是TWIP,其中WTIP是一个点的0.05,而一个点是1/72英寸,所以WTIP相当于1/1440英寸,即6.9*10(-4)英寸,(点是衡量字字体的单位),x轴和y轴的方向与MM_LOENGLISH相同15.2 Visual C++中的绘图机制15.2.1 应用程序中的视图类
类定义了包括几个虚函数和理写,不过我们在此处着重介绍一个函数是OnDraw(),每当需要重新绘制文档窗口的客户区时,都将调用这个函数,当程序接收到WM_PAINT消息时,应用程序架构调用的正是这个函数
OnDraw()成员函数由MFC Application Wizard创建的OnDraw()成员函数实现如下所示
//pDC
void CSketcherView::OnDraw(CDC* )
{SCketcherDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);//只是确保指针pDoc包含有效的地址if(!pDoc){return;}
}15.2.2 CDC类
应当使用CDC类的成员在程序中完成所有绘图,这个类的所有对像和它派生的类都包含把图形和文本发送到显示器和打印机时需要的设备环境和成员函数1 显示图形
//在设备环境中,您将绘制与当前位置相关的实体,如直接,圆和文本,当前位置是客户区中的一个点,它或者由以前绘制的实体设置,或者是通过调用函数对它进行设置,
void CSketcherView::OnDraw(CDC* pDC)
{SCketcherDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);//只是确保指针pDoc包含有效的地址if(!pDoc){return;}pDC->MoveTo(50,50);//这个成员函数只针对被指定为参数的x和y坐标设置当前位置,CPoint MoveTo(int x, int y);CPoint MoveTo(POINT aPoint);POINT类型的参数,它是一个具有如下定义的结构typedef struct tagPOINT{LONG x;LONG y;} POINT;LONG这种类型在windows API中定义,对应于32位符号整数}绘制直接
在对OnDraw()函数中的MoveTo()调用以后,调用函数LineTo(),这将在客户区中绘制一条直线CDC类还定义两个牒一的LineTo函数
BOOL LineTo(int x, int y);
BOOL LineTo(POINT aPoint);void CSketcherView::OnDraw(CDC* pDC)
{SCketcherDoc* pDoc = GetDocument();ASSERT_VALID(pDoc);//只是确保指针pDoc包含有效的地址if(!pDoc){return;}pDC->MoveTo(50,50);pDC->LineTo(50,200);pDC->LineTo(150,200);pDC->LineTo(150, 50);pDC->LineTo(50,50);
}绘制圆
在绘制圆时,CDC类中有几种函数成员可供选择,不过它们全都是设计用于绘制椭圆的,
由高中几何可知,圆是椭圆的一种特例,是长轴等于短轴的随圆,因此可以使用成员函数Ellipse()绘制圆和CDC类支持的其他闭合形状一样,Ellipse()函数将利用设置的颜色填充形状的内部,内部颜色由选入设备环境的画刷确定,设备环境中的当前画刷确定如何填充闭合形状绘制不进行填充的圆的另一种方法是使用Arc()函数,它不涉及画刷,其优点是可以绘制椭圆的任意一段弧,而不是完整曲线,这个函数在CDC类中有两个版本BOOL Arc(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
BOOL Arc(LPCRECT lpRect, POINT StartPt, POINT EndPt);2 利用颜色绘图
绘图意味着要使用有颜色的宽度的画笔对像,并且我们一直在使用设备环境中提供的默认画笔对像,当然,并不强迫您这么做
创建具有给定宽度的颜色的画笔,MFC定义的类CPen可以提供帮助创建画笔
创建画笔的最简单方法是首先声明一个CPen类
CPen aPen;
BOOL CreatePen (int aPenStyle, int aWidth, COLORREF aColor);
第一个参数是定义绘图时需要使用的线型
PS_SOLID 绘制实线
PS_DASH 绘制虚线,只有在把画笔宽度指定为1时,这种线型才有效
PS_DOT 绘制点线,只有在把画笔宽度指定为1时,这种线型才有效
PS_DASHDOT 绘制一划一点相间的直接,只有在把画笔宽度指定为1时,这种线型才有效
PS_DASHDOTDOT 绘制一划双点相间的直线,只有把画笔宽度指定为1时,这种线型才有效
PS_NULL 不进行任何绘制
PS_INSIDEFRAME 绘制实线,但是和PS_SOLID不同,指定实线的点出现在画笔的边缘而不是中心,所以绘罎的对像永远不会超出封闭矩形CreatePen()函数第二个参实定义线宽最后一个参数指定利用画笔绘图时使用的颜色
aPen.CreatePen(PS_SOLID, 2, RGB(255, 0, 0));使用画笔
要使用画笔,必须把它选入正在绘图的设备环境中,为此需要使用CDC类成员函数SelectObject()
CPen* pOldPen = pDC->SelectObject(&aPen);
要恢复以前的画笔,只需要再次调用这个函数,以传递从最初调用返回的指针
pDC->SelectObject(pOldPen);创建画刷
CBrush类的对像封装了Windows画刷,可以把画刷定义成纯色,影线或者有图案的画刷
画刷实际上是一个8*8的像素块,它在要填充的区域上重复应用
要定义纯色的画刷,可以在创建画刷对像的时指定颜色CBrush aBrush(RGB(255,0,0));
可以使用另一种构造函数定义影线画刷,这需要指定两个参数,和以前一样,第一个参数定义影线的类型,第二个参数指定颜色,影线参数可以是下列符号常量之一HS_HORIZONTAL  水平影线
HS_VERTICAL  垂直影线
HS_BDIAGONAL 从左到右的45下行影线
HS_FDIAGONAL 从左到右的45上行影线
HS_CROSS 水平和垂直交叉影线
HS_DIAGCROSS 45交叉影线CBrush aBrush(HS_DIAGCROSS, RGB(255,0,0));
在初始化CBrush对像时,也可以使用类似于初始化CPen对像时的方式,对纯色画刷使用CBrush类的CreateSolidBrush()成员函数,对影线画刷使用这个类的CreateHatchBrush()成员函数
它们需要在参数和对应的构造数相同CBrush aBrush;
aBrush.CreateHatchBrush(HS_DIAGCROSS, RGB(255,0,0));使用画刷
第种标准画刷都由预定义的符号常量标识,可以使用的画刷有7种,它们分别是
CRAY_BRUSH
BLACK_BRUSH
HOLLOW_BRUSH
LTGRAY_BRUSH
WHITE_BRUSH
NULL_BRUSH
DKGRAY_BRUSH
pDC->SelectStockObject(NULL_BRUSH);
在SelectStockObject()函数中还可以使用标准画笔
SelectStockObject()函数返回的指针指向设备环境中被替换的对像,这样就可以把这个对像保存起来,并在完成绘图以后进行恢复在于使用库存画刷,然后在完成绘图后恢复以前的画刷这样一种情况
CBrush* pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);pDC->SelectObject(pOldBrush);15.3 实际绘制图形15.4 对鼠标进行编程
1 按下鼠标表示绘图操作开始
2 按住鼠标时鼠标指针的位置定义形状态的参考点
3 在检测到鼠标器键按下后,鼠标的移动表示要绘制一个形状态,鼠标指针位置为这个形状提供一个定义点
4 释放鼠标键时鼠标指针的位置表示应当绘制的最终形状
可以猜测到,所有这些信息都由Windows以发送到程序的消息的形式提供,直接和圆的绘制过程的实现几乎完全由编写消息处理程序组成15.4.1 鼠标发出的消息
了解如下所示的三种鼠标消息
WM_LBUTTONDOWN 按下鼠标左键时出现消息
WM_LBUTTONUP 释放鼠标左键时出现的消息
WM_MOUSEMOVE 移动鼠标时出现的消息1 WM_LBUTTONDOWN
这种消息将启动绘制元素的过程,所需要:
(1) 注意元素绘制过程已经开始
(2) 把鼠标指针的当前位置作为定义元素的第一个点记录下来2 WM_MOUSEMOVE这是一个中间阶段,其中将创建和绘制当前元素的临时版本,但是鼠标左键必须处理按下状态,所以需要(1) 检查左键是否已经按下(2) 如果已经按下,则删除已经绘制的当前元素的前一个版本(3) 如果没有按下,则退出(4) 把鼠标指针的当前位置记录为元素的第二个定义点(5) 使用这两个定点绘制当前元素3 WM_LBUTTONUP(1) 存储由记录的第一个点定义的元素的最终版本,同时存储鼠标键在第二个点释放时指针的位置(2) 记录元素绘制过程的结束下面将生成这三种鼠标消息的处理程序15.4.2 鼠标消息处理程序//类中传递到处理程序的参数有两个,即nFlags和point,nFlags是UNIT类型号,它包含很多表明是否按下各种键的状态标志等,point是CPoint对像,它定义按下鼠标左键时鼠标指针的位置,UNIT类型号在windows API中定义,它对应于32位无符号整数//传递到函数的nFlags的值可以是下列符号值的任意组合MK_CONTROL  对应于按下Ctrl键
MK_LBUTTON  对应于按下鼠标左键
MK_MBUTTON  对就于按下鼠标中间键
MK_RBUTTON  对应于按下鼠标右键
MK_SHIFT  对应于按下Shift键在消息处理程序中,如果能够检测是否按下一个键,那么根据发现的其他情况,就可以对消息进行不同的处理,nFlags的值可以包含一个以上这样的指示符,每个指针符都对应于这个字中的一个特定位,所以可以使用按位与运算符测试特定的键,例如,要测试是否按下了Ctrl键
if(nFlags & MK_CONTROL){
}
如果nFolags变量具有由MK_CONTROL集合定义的位,那么表达式nFlags&MK_CONTROL的值只能是TRUE
这样,在按下鼠标左健时,根据是否也按下了Ctrl键,可以采取不同的动作,由于此处使用的是按位与运算符,所以对应的位将一起进行与运算,不要把这个运算符同逻辑与运算符&&相混淆,它无法完成这里的运算传递到其他两种消息处理程序的参数和OnLButtonDown()函数相同,针对它们生成的代码是15.4.3 使用鼠标绘图1 重新绘制客户区
绘制或删除元素牵涉到重新绘制窗口的整个或部分客户区
通过调用视图类的继承成员InvalidateRect()函数,可以告知Windows应当绘制的特定区域
这个函数接受两个参数,第一个参是指RECT或CRect对像的指针,这些对像将在需要重新绘制的客户区中定义矩形,
如果这个参数的值是空值,那么整个客户区将被重绘制,第二个参数是bool值,如果准备去掉矩形的背景
那么这个BOOL的值是TRUE,否则为FALSH因此在绘新创建的形状态时,必须完成以下工作:
(1) 确保视图类中的OnDraw()函数在重新绘制的重新绘制窗口时包括新创建的项
(2) 调用InvalidateRect()函数,这时将向待重新绘制形状的边界矩形的指针作为第一个参数传递删除一个形状,需要完成下列工作:
(1) 从OnDraw()函数将要绘制的项中删除这个形状
(2) 调用InvalidateRect()函数,这时第一个参数指向待删除形状的边界矩形2 定义元素的类
我们需要以某种方式把元素存储到一个文档中,如果要使用草图具有永久性,还必须能够把这个文档存储到一个文件中,以便今后检索,后面将详细地讨论文件操作,就目前而言,知道MFC类CObject包括大气层需要的工具就足够了
另外一个问题,就是无法提前知道用户创建的元素类型的顺序,Sketcher程序必须能够处理任何顺序的元素
这意味着在选择特定元素类函数时,使用基类指针可能会使事情简单一些
CObject
CElement
CLine CRectangle  CCircie  CCurve在视图中存储临时元素
在前面讨论如何绘制形状时已经介绍过,按下鼠标左键以后,拖动鼠标将创建和绘制一系列临时元素对像,
既然现在已经知道所有形状态的基类都是CElement,那么就可以添加指向这个视图类的指针
用以存储临时元素的地址3 CElement类
有些数据项(如颜色)显然对于所有类型的元素都是通用的,所以可以把它们放在CElement类中,以便可以在每个派生类中继承它们,但是在定义特定元素属性的类中
有些数据成中却极其不同,所以需要在它们所属的特定派生类中声明这些成员注意:
串行化是将对像写入到文件的通用术语,C++/CLI应用程序中串行化的工作方式与MFC中串行化的工作方式存在区别4 CLine类5 实现CLine类
CLine类构造函数
绘制直接创建边界矩形
用于绘形状的矩形称作为"封闭矩形",而把考虑到画笔宽度的矩形称作为"边界矩形"以此区分它们
在计算不同映射模式中边界矩形的坐标时,计算方法之间的区虽只与y坐标有关,x坐标的计算对于所有映射模式都一样,在MM_TEXT映射模式中,计算边界矩形的各个角时,要从定义矩形的左上角的y坐标中减去线条宽度,在右下角的y坐标中加上线条宽度,但是在MM_LOENGLISH映射模式()以及其他所有映射模式中,由于y轴在相反的方向上增大,因此需要的在定义矩形的左上角的y坐标中加上线条宽度,在右下角的y坐标中减去线条宽度,对于所有映射模式来说,都要从定义矩形的左上角的x坐标中减去线条宽度,在右下角的x坐标中加上线条宽度规范化的矩形
InflateRect()函数从矩形的top和left成员中减去给定的值,给bottom和right成员加上这些值,这意味着,如果矩形不是规范化的,那么矩形实际上有可能缩小
规范化矩形的left值小于或等于right值,top值小于或等于bottom值,通过调用CRect对的NormalizeRect()成员
可以确保这个对像是规范化的,大部分CRect成员函数为了正常工作,都要求这个对像要规范化,所以在m_EnclosingRect中存储封闭矩形时,必须确保它是规范化的6 计算直接的封闭矩形
现在需要做的就是在直线的构造函数内编写计算封闭矩形的代码7 CRectangle类
虽然在定义矩形对像时使用的数据和定义直接时相同--矩形对角线上起点和终点,但是现在不需要存储定义点,由基类继承而来的数据成员中的封闭矩形将完整地定义矩形这个形状,所以不需要任何数据成员,因此可以把CRectangle类定义为;绘制矩形
有一个称作Rectangle()的CDC类成员可以绘制矩形,这个函数将绘制闭合图形,然后利用当前画刷进行填充
您也许认为这完全不符合您的要求,这时只要选择NULL_BRUSH就完全可以绘制出您需要的形状,另外还有一个函数PolyLine(),它根据一组点绘制由多条线段组成的形状,当然也可以再次使用LineTo(),但是最容易的方法是使用Rectangle()函数8 CCircle类
CCircle类的接口和CRectangle类完全相同,只根据圆的封闭矩形就可以绘制圆
实现CCircle类
如前所述,在创建圆时,按下鼠标左键时的点将成为圆心,移动鼠标指针以后,释放鼠标左键时的点将是最终圆的圆周上的一个点,构造函数的工作是把这些点转换成可以在定义圆的类中使用的形式
CCircle类构造函数我们可以计算封闭矩形的左上角和右下角的点相对于圆心(x1, y1)的坐标,圆心是在按下鼠标左键时记录的点,假设映射模式是MM_TEXT,计算左上角点的坐标时,只需要从圆心的坐标中减去半径
类似地,把圆心的x和y坐标分别加上半径,就可以得到右下角点的坐标,因此,可以把CCircle类构造函数的代码编写为绘制圆
由于已经了解了如何使用CDC类中的Arc()函数绘制圆,因此现在将使用Ellipse()函数绘制圆,9 CCurve类
CCurve类不同于其他类,因为它必须能够处理数量可变的定义点,这就需要维护某种列表,尽管如此您可以使用TSL模板定列表,但是这种列表的缺点在于不能串行化,由于第16章将讨论如何创建可串行化的列表,所以现在先不讨论这个类的细节,就目前而言,可以包括一个提供哑成员函数的类定义,这样就可以对包含调用这些函数的代码进行编译和链接10 完成鼠标消息处理程序
鼠标进行移动时,这个处理程序只绘制元素的一系列临时版本,因为最终的元素是在释放鼠标左键时创建时,因此,可以把像拉橡皮筋那样绘制临时元素的过程看作是这个函数的局部操作
而由视图的OnDraw()函数成员绘制元素的最终版本,这种方法使橡皮筋元素的绘制变得非常有效率,因为它不涉及到最后负责绘制完整文档的OnDraw()函数
利用CDC类的一个成员SetROP2(),可以做得更好,这个成员函数特别适合于橡皮筋操作设置绘图模式
在与CDC对像相关联的设备环境中,SetROP2()函数为所有后续输出操作设置绘图模式
这个函数名中的"ROP"代表光栅操作(Raster OPeration),因为绘图模式的设置将应用于尖栅显示器R2_BLACK  所有绘图颜色都是黑色
R2_WHITE  所人绘图颜色都是白色
R2_NOP    不进行任何绘图操作
R2_NOT    绘图颜色是屏幕颜色丰富的的反色,这将确保输出清晰可见,困烃它防止绘图颜色与背景颜色相同
R2_COPYPEN  绘图颜色是画笔颜色,如果不行设置,这就是默认的绘图模式
R2_NOTCOPYPEN  绘图颜色是画笔颜色的反色
R2_MERGEPENNOT  绘图颜色是画笔颜色和背景颜色的反色“相或”以后产生的颜色
R2_MASKPENNOT  绘图颜色是画笔颜色和背景颜色的反色"相与"以后产生的颜色
R2_MASKPENNOT  绘图颜色是背景颜色和画笔颜色的反色"相或"以后颜色的颜色
R2_MASKNOTPEN  绘图颜色是背景颜色和画笔颜色的反色"相与"以后产生的颜色
R2_MERGEPEN    绘图颜色是背景颜色和画笔颜色"相或"以后产生和颜色
R2_NOTMERGEPEN 绘图颜色是R2_MERGEPEN颜色的反色
R2_XORPEN      绘图颜色是画笔颜色和背景颜色"异或"以后产生和颜色
R2_NOTXORPEN   绘图颜色是R2_XORPEN颜色反色白色是由相同比例,最大数量的约色,蓝色和绿色构成的,为了简化问题,可以把白色表示为(1,1,1,)
这三个值代表颜色的RGB成分,在相同的方案中,红色被定义为(1,0,0)计算过程
背景颜色--白色  1  1  1
画笔颜色--红色  1  0  0
XOR             0  1  1
NOT XOR--产生红色  1  0  0
因此,第一次在白色背景上绘制红色直接时,如上图的最后一行所示,直线显示和颜色是红色,如果第二次绘制的相同直接覆盖在现有的直线上,那么重写的背景像素将是红色,产生的绘图颜色将作如
背景颜色-红色   1-0-0
画笔--白色      1-0-0
XOR             0-0-0
NOT XOR--产生白色 1-1-1
此处需要注意使用正确的背景颜色,应当看到,使用白色画笔在红色背景上绘图的效果不太好,如第一次绘制的形状是红色,其结果是看不见的,它第二次出现的是白色,如果在黑色背景上进行绘制,如同在白色背景上那样,形状将出现,然后消失,但是它们不是以选择的画笔颜色绘制的编写OnMouseMove()处理程序创建元素处理WM_LBUTTONUP消息
WM_LBUTTONUP消息完成创建元素的过程,这种消息的处理程序的工作是把元素的最终版本传递到文档对像,然后清理视图对像数据成员,在创建和编辑这种处理程序的代码时,可以采用和前面代友相同的方法15.5 练习使用Sketchar程序15.5.1 运行示例15.5.2 捕获鼠标消息15.6.1 在窗体上绘图
在CLR程序中,当用户在窗体上绘图时没有任何复杂的映射模式,绘图目标的初始位置位于窗体的左上角,x,x轴的正方向为从左到右,y轴的正方向为从上到下,用于在窗体上绘图的类位于System::Drawing命名空间中,并且由Form1类中处理Paint事件的函数执行在窗体上绘图的操作,在CLRSketcher的Design窗口中,
右击窗体并从弹出式菜单中选择Properties
选择Events按钮以显示窗体的事件,然后双击Paint事件;在Properties窗口中,Paint事件是Appearance组中的唯一事件,双击该事件生成Form1_Paint()函数,为了响应必须重绘窗体时产生的Paint事件调用该函数15.6.2 添加鼠标事件处理程序
操作事件是MouseDown,MouseMove, MouseUp事件,
MouseDown事件在按下鼠标时发生,根据传递给相应事件处理程序的信息确定接下哪里个鼠标键
MouseUp事件在释放鼠标键时发生,通过传递给该事件处理程序的参数了解释放了哪里个鼠标键//第一参数标识事件源
//第二参数提供关于该事件的信息,传递给该处理程序函数的MouseEventArgs对像//实际上,所有的鼠标事件处理程序都有该类型的参数,包含一些属性,这些属性提供了可以在处理事件时使用的信息
Button:枚举类System::Windows::Forms::MouseButtons的属性,该属性标识按下哪里个鼠标键MouseButtons 枚举为该属性定义了如下可能的值:MouseButtons::Left  鼠标左键MouseButtons::Right 鼠标右键MouseButtons::None  没有按下任何鼠标键MouseButtons::Middle 鼠标中间键MouseButtons::XButton1 第一个XButtonMouseButtons::XButton2 第二个XButton
Location类型为System::Drawing::Point的属性,该属性标识鼠标指针的位置,Point对像的X和Y属性是x和y坐标的整数值
X   作为int类型值的鼠标旨针的x坐标
Y   作为int类型值的鼠标指针的y坐标
Clicks  按下或释放鼠标键次数的int类型计数值
Delta  鼠标滚轮旋转次数的有正负之分的int类型计数值在Form1类中添加两个私有的数据成员,我为drawing的bool变量,用于记录当前是否在绘制元素
如为firstPoint的Point类型变量,用于记录初始的鼠标指针位置,可以手工执行该操作15.6.3 定义C++/CLI元素类
应用程序的代码在CLRSketcher命名空间中定义,因此将元素类的定义放入相同的命名空间中, Element类和它的子类必须是引用类,因为值类不可能是派生类,
Element类也必须被定义为abstract,因为没有Draw()函数的实现,在每个派生类中将重写Draw()函数以绘制特定类型的元素,您将以多态的方式调用该函数Position成员的类型为System::Drawing::Point,这是定义具有两个成员X和Y的点对象的值类型,派生类中将继承position,color和boundRect成员,这些成员将存储元素的位置,颜色和边界矩形,相对于点position绘制所有元素,此刻不需要关心边界矩形和封闭矩形之间的距离,
顺带提及的的,boundRect变量的类型名System::Drawing::Rectangle在此处理完全限定的名称,因为将添加名为Rectangle的派生类,如果此处没有使用完全限定的名称,编辑器就会假定在这个头文件中使用Rectangle类1 定义直接2 定义颜色
System::Drawing::Color是封装ARGB颜色值的值类,ARGB颜色是32位的值绘制直线
Draw()函数将使用作为参数传递的System::Drawing::Graphics对像,以适当的颜色绘制直线,Graphics类定义了大量用于绘制形状的函数DrawLine(Pen pen, Point p1, Point p2)使用pen绘制从p1到p2的直线,Pen对像以特定的颜色和线宽绘制直线DrawLine(Pen pen, int x1, int y1, int x2, int y2)使用pen绘制从(x1,y1)到(x2,y2)的直线DrawLines(Pen pen, Point[] pts)使用pen绘制连接pts数组中的点的一系列直接DrawRectangle(Pen pen, Rectangle rect)使用pen绘制矩形rectDrawRectangle(Pen pen, int X, int Y, int width, int height)使用pen在(x,y)位置绘制矩形,该矩形的尺寸由width和height指定DrawEllipse(Pen pen, Rectangle rect)使用pen绘制由边界矩形rect指定的椭圆DrawEllipse(Pen pen, int x, int y, int width, int height)使用pen绘制椭圆,该椭圆由位于(x,y)位置,尺寸为width为height的边界矩形指定定义用于绘图的画笔
System::Drawing::Pen类代表绘制直接和曲线的画笔Pen^ pen = gcnew Pen(Color::CornflowerBlue);
定义了可以用于浅蓝色进行绘图的Pen对像Pen^ pen = gcnew Pen(Color::Green, 2.0f);
定义了绘制线宽为2.0f的绿色直线的Pen对像,注意,画笔宽度是公共属性,pen->Width = 3.0f;Line类中的Draw()函数的定义
virtual void Draw(Graphics^ g) override
{g->DrawLine(gcnew Pen(color), position, end);
}默认的Pen对像可以绘制1.0f默认宽度的连接直接Pen的其它属性
Color获取或设置画笔的颜色,这里类型为System::Drawing::Color的值,例如,为了设置Pen对像的绘图颜色为红色,设置该属性如下 Pen->Color = Color::Red;Width 获得或设置画笔绘制的直线的宽度,这是类型为float的值DashPattern 获得或设置float值的数组,该float值指定为了直接的点样式,这些数组值指定了直接中交替的点和空格的长度array<float>^ pattern = {5.0f, 2.0f, 4.0f, 3.0f};pen->DashPattern = pattern;该语句定了如下的样式,首先长度为5的点,后跟长度为2的空格,再跟上长度为4的点,最后跟上长度为3的空格,根据需要在直接中多次重复使用该样式DashOffset指定从直接起点到点样式的开始位置之间的距离,这是float类型的值StartCap指定直接直点处理的帽型(cap style),帽型由System::Drawing::Drawing 2D::LineCap枚举定义,该枚举定义了如下可能的值Flat, Square, Round, Triangle, NoAnchor, SquareAnchor, RoundAnchor,DiamondAnchor, ArrowAnchor, Custom, AnchorMask例如, 为了绘制起点处为回旋帽(round line cap)的直线,设置该属性如下pen->StartCap = System::Drawing::Drawing2D::LineCap::Round;EndCap 指定直接终点的帽型,直线终点的帽型的可能值与StartCap相同事标准画笔
有时您可能并不需要灵活地改变所使用的Pen对像的属性,System::Drawing::Pens定义了
大量标准画笔,这些画笔以给定颜色绘制度为1的直线,例如,Pens::Black和Pens::Beige分别是以黑色和米苋公绘图的标准的画笔,注意,不可以修改标准画笔--所见即所得2 定义矩形3 定义圆15.6.4 实现MouseMove事件处理程序15.6.5 实现MouseUp事件处理程序MouseUp事件处理程序的任务是存储草图中的新元素,将tempElement还原为nullptr,将drawing指示器还原为flash,并且重绘草图15.6.6 实现窗体的Paint事件处理程序
前面生成的Paint事件委托有两个参数,
第一个类型为Object^ 的参数标识事件源,
第二个类型为System::Windows::Forms::PaintEventArgs的参数提供有关该事件的信息,特别需要指出的是,该参数Graphics属性提供了用于在窗体上绘图的Graphics对象15.7 小结
1 认情况下,windows使用原点在客户区左上角的客户坐标系统处理窗口的客户区x轴的正方向从左到右,Y轴的正方向从上到下2 只能使用设备环境在窗口的客户区中绘图3 为了处理窗口的客户区,设备环境提供了大量称为映射模式的逻辑坐标系统4 映射模式的默认原点位置在客户区的左上角,默认的映射模式是MM_TEXT,它提供以像素为单位的坐标,在这种模式中,X轴的正方向从左到右,y轴的正方向从上到下。5 尽管平常可以绘制临时实体,但是在响应WM_PAINT消息时,程序始终应当在窗口的客户区中绘制永久性内容,对应用程序文档的所有绘制都应当从视图类的OnDraw()成员函数进行控制,在应用程序接收到WM_PAINT消息时,将调用这个函数6 通过调用视图类的InvalidateRect()函数成员,可以标识希望重新绘制的那部分客户区。当下一个WM_PAINT消息发送到应用程序时,Windows将把这个区域作为参数传递给要重新绘制的整个区域7 windows向应用程序发送有关鼠标事件的标准消息,利用Class Wizard可以创建处理这些消息的处理程序8 通过在视图类中调用SetCapture()函数,可以将所有鼠标消息发送到应用程序,在完成这一操作时,必须通过调用ReleaseCapture()函数释放鼠标键,否则,其他应用程序将不能接收鼠标消息9 在创建向何实体时,通过在处理鼠标移动的消息处理程序中绘制它们,可以实现橡皮筋操作10 利用CDC类的SetROP2()成员可以设置绘图模式,选择正确的绘图模式将大大简化橡皮筋操作11 使用Form Design功能,可以交互式的创建CLR程序和CUI元素,可以将Toolbox窗口上的控件直接拖动到窗体上,当然,通过手工添加合适的代码,也可以通过编程方式创建GUI元素12 通过设置GUI控件的属性,可以在窗体上定制这些GUI控件13 通过GUI组件的Properties窗口也可以自动添加事件处理程序函数14 Graphics类定义了用于在窗体上绘图的函数15 Pen类定义了以给定颜色的线型绘图的对像练习题没有做好,失败一次*/

  

转载于:https://www.cnblogs.com/xiangxiaodong/archive/2012/12/02/2798380.html

Visual C++ 2008入门经典 第十五章 在窗口中绘图相关推荐

  1. c++学习书籍推荐《Visual C++2008入门经典》下载

    百度云及其他网盘下载地址:点我 <Visual C++2008入门经典>学习目标: 使用标准模板库(STL)来组织和操作本地C++程序中的数据 C++程序调试技术 构造Microsoft ...

  2. Visual C++ 2008入门经典 Ivor Horton

    Visual C++ 2008入门经典    Ivor Horton 本书系编程语言先驱者Ivor Horton的经典之作,是C++编程方面最畅销的图书品种之一,不仅涵盖了Visual C++ 200 ...

  3. Visual C++ 2008入门经典 Ivor Horton(书_在线阅读)

    http://book.51cto.com/art/200912/173520.htm 本书系编程语言先驱者Ivor Horton的经典之作,是C++编程方面最畅销的图书品种之一,不仅涵盖了Visua ...

  4. Visual C++ 2008入门经典 第四章数组 字符串(练习题)

    //练习题一:/*int arraySize = 5; //数组的长度double* values = new double[arraySize]; //初始化一个values的指针,成员为五个dou ...

  5. Visual C++ 2008入门经典 第二十一章更新数据源

    /* 第二十一章更新数据源 本章主要内容:1 数据库事务2 如何使用记录集对像更新数据库3 如何在更新操作中将数据从记录集传输到数据库4 如何更新表中的现有行5 如何添加新行到表中21.1 更新操作2 ...

  6. Visual C++ 2008入门经典 第九章类的继承和虚函数

    // 第九章类的继承和虚函数 //.cpp: 主项目文件. //1 继承如何与面向对像的编程思想适应 //2 根据现有类定义新类 //3 使用protected关键字为类成员指定新的访问特性 //4 ...

  7. Visual C++ 2008入门经典 第四章数组 字符串

    /* //学习内容 数组及其使用方法 如何声明和初始化不同类型的数组 如何声明和使用多维数组 指针及其使用方法 如果声明和初始化不同类型的指针 数组和指针之间的关系 引用的概念及声明方法,关于使用引用 ...

  8. Visual C++ 2008入门经典 第九章类的继承和虚函数(二)

    //9.6.7 虚析构函数 /*#include "stdafx.h" #include <iostream> using namespace std; using n ...

  9. Visual C++ 2008入门经典 第十章标准模板库(二)

    //10.4 关联容器 //关联容器(如map<K,T>)最重要的特性是无需搜索就可检索特定对像,关联容器内容T类型对像的位置由与对像一起提供的类型为K的键确定,因此只要提供适当的键就可以 ...

最新文章

  1. 如何查看java对象的大小
  2. 新型消防机器人作文_消防机器人
  3. 洛谷 P3182 [HAOI2016]放棋子(错排问题)
  4. FastReport.Net使用:[36]续表
  5. 【django】如何搭建虚拟环境(解决mkvirtualenv:未找到命令)
  6. python引入redis_十六大Python面试题!看完面试官给了我40K的薪资
  7. BigDecimal 往左移动两位小数_一课研究之“让问题意识成为学生深度学习的钥匙——除数是整数的小数除法例谈”20190830...
  8. 病毒及***防御手册之十二
  9. DHCP服务器如何检测穿过中继代理的IP地址冲突(gratuitous ARP肯定是不行的)
  10. 资源监视工具 Glances
  11. 温故而知新:new与override的差异以及virtual方法与abstract方法的区别
  12. krpano html5略缩图边框颜色,krpano加载场景缩略图列表
  13. IMA-ADPCM 算法
  14. 菜鸟学习C++之Console Application
  15. spring mvc数据绑定与表单标签库
  16. Seckill秒杀系统高并发优化
  17. 在线LOGO的设计工具推荐
  18. Jcrop+ajaxFileUpload 图片裁切上传 oss(java web)
  19. 阿里开源的升级思考:开源委员会的三个关键行动点
  20. 个人网站必备的 10 个开源后台管理UI库

热门文章

  1. Android性能优化最佳实践,终局之战
  2. 哈尔滨理工大学ACM集训第二周总结
  3. 【408预推免复习】操作系统之存储器管理
  4. 【Linux入门到精通系列讲解】shell中的eval命令
  5. 【深度学习入门到精通系列】Recurrent和Residual解释
  6. 算法提高 学霸的迷宫
  7. 搭建Ubuntu18.04+Anaconda3.x+Pycharm+SimpleITK(一)
  8. java linux res很高_Linux下Java进程RES是1.6G,但是jmap里用到的才五百多M,剩下的1.1G左右是去哪了?...
  9. 网站建设全阶段培养共分三期
  10. 5训练需要更改参数吗_这就是需要的瘦肚子训练,5个杠铃片腹肌训练动作暴汗燃脂瘦腰腹...