zoukankan      html  css  js  c++  java
  • Visual C++ 2008入门经典 第十五章 在窗口中绘图 简单

    /*
    
    第十五章 在窗口中绘图
    主要内容:
    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 第一个XButton
    	MouseButtons::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绘制矩形rect
    
    DrawRectangle(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类定义了以给定颜色的线型绘图的对像
    
    练习题没有做好,失败一次
    
    */
    

      

  • 相关阅读:
    python笔记之re模块学习
    python笔记之面向对象
    C# 静态类和非静态类(实例类)
    占位符的使用
    数据类型和数据类型转换
    win7 安装 memcached
    php 汉字转换成拼音
    apache window环境下本地配置虚拟主机
    在浏览器输入一个网址到得到页面的过程
    浅谈线程池ThreadPoolExecutor核心参数
  • 原文地址:https://www.cnblogs.com/xiangxiaodong/p/2798380.html
Copyright © 2011-2022 走看看