C#学习笔记 :图形绘制基础

在Windows的用户界面中,当创建一个窗口,并在该窗口进行绘图时,一般要声明一个派生于System.Windows.Forms.Form的类。如果要编写一个定制控件,就要声明一个派生于System.Windows.Forms.UserControl的类。在这两种情况下,都重写了虚拟函数OnPaint()。只要窗口的任何一部分需要重新绘制,Windows都会调用这个函数。
在这个事件中,PaintEventArgs类是一个参数。在PaintEventArgs中有两个重要的信息:Graphics对象和ClipRectangle对象。

Graphics类:
这个类封装了一个GDI+绘图界面。有3种基本类型的绘图界面:
l         Windows和屏幕上的控件
l         要发送给打印机的页面
l         内存中的位图和图像
Graphics类提供了可以在这些绘图界面上绘图的功能。在其他功能中,我们可以使用它绘制圆弧、曲线、Bezier曲线、椭圆、图像、线条、矩形和文本。
给窗口获得Graphics对象有两种不同的方式。首先是重写OnPaint()事件,该事件是一个Form类继承Control类的虚拟方法。下面利用从该事件的PaintEventArgs中获取Graphics对象:
            protected override void OnPaint(PaintEventArgs e)
            {
                Graphics g = e.Graphics;
                // do our drawing here
            }
有时,需要直接在窗口中绘图,而无需等待OnPaint()事件。例如要编写代码,选择窗口中的某些图像(类似于在Windows Explorer中选择图标),或者用鼠标拖动一些对象,就是这种情况。在窗体上调用CreateGraphics()方法就可以获得一个Graphics对象,这是Form类继承Control类的另一个方法:
            protected void Form1_Click(object sender, System.EventArgs e)
            {
                Graphics g = this.CreateGraphics();
                // do our drawing here
                g.Dispose();    // this is important
            }
只有在无用存储单元收集器(GC)调用了析构函数时,我们才不必调用Dispose(),但不能确保GC何时运行。所以很可能在释放这些资源前系统资源就被用尽了,所以需要手动释放这些资源。还有一种方法就是使用using关键字,在对象超出作用域时using结构会自动调用Dispose()。
            using(Graphics g = this.CreateGraphics())
            {
                g.DrawLine(Pens.Black,new Point(0,0),new Point(3,5));
         }

坐标系统:
GDI+的坐标系统建立在通过像素中心的假想数学直线上,这些直线从0开始,其左上角的交点是X=0,Y=0(简短记号是(0,0)/Ponit(0,0)。
在绘制线条时,GDI+ 会把绘制出来的像素在指定的数学直线上对中。在绘制整数坐标的水平线时,可以认为每个像素的一半落在假想数学直线的上半部分,而另一半落在假想数学直线的下半部分。
这里有一点需要注意的地方,如果指定了宽度为5(例如画一个从(1,0)到(6,4)的矩形),就会在水平方向上绘制6个像素。但如果考虑到数学直线通过像素中心,则该矩形只有5个像素宽,绘制的线条有一半像素落在假想数学直线的外面,一半像素则落在假想数学直线的里面。
不仅如此,如果使用图形保真技术进行绘图,其他像素就会上一半的颜色,创建出光滑的线条,部分避免了对角线的“台阶”外观。
在绘图时,常常用3种结构指定坐标:Point,Size和Rectangle。
Point:
GDI+使用Point表示一个点。这是一个二维平面上的点——一个像素的表示方式。许多GDI+函数例如DrawLine(),以Point作为其参数。声明和构造Point的代码如下所示:
Point p = new Point(1,1);
通过其公用属性可以获得和设置Point的X和Y坐标。
Size:
GDI+使用Size表示一个尺寸(像素)。Size结构包含宽度和高度。声明和构造Size的代码如下所示:
Size s = new Size(5,5);
通过其公用属性可以获得和设置Size的宽度和高速。
Rectangle:
有两个构造函数。一个构造函数的参数是X坐标、Y坐标、宽度和高度。另一个构造函数的参数是Point和Size结构(Point定义矩形的左上角,Size定义其大小)。声明方式如下:
            Rectangle r1 = new Rectangle(1,2,5,6);

            Point p = new Point(1,2);
            Size s = new Size(5,6);
            Rectangle r2 = new Rectangle(p,s);
Rectangle的成员:
公共字段:
Empty:表示其属性未被初始化的 Rectangle 结构。
公共属性:
Bottom:获取此 Rectangle 结构下边缘的 y 坐标。
Height:获取或设置此 Rectangle 结构的高度。
IsEmpty:测试此 Rectangle 的所有数值属性是否都具有零值。
Left:获取此 Rectangle 结构左边缘的 x 坐标。
Location:获取或设置此 Rectangle 结构左上角的坐标。
Right:获取此 Rectangle 结构右边缘的 x 坐标。
Size:获取或设置此 Rectangle 的大小。
Top:获取此 Rectangle 结构上边缘的 y 坐标。
Width:获取或设置此 Rectangle 结构的宽度。
X:获取或设置此 Rectangle 结构左上角的 x 坐标。
Y:获取或设置此 Rectangle 结构左上角的 y 坐标。
公共方法:
Ceiling:通过将 RectangleF 值舍入到比它大的相邻整数值,将指定的 RectangleF 结构转换为 Rectangle 结构。
Contains:已重载。确定指定的点是否包含在此 Rectangle 定义的矩形区域范围内。
Equals:已重写。测试 obj 是否为与此 Rectangle 结构具有相同位置和大小的 Rectangle 结构。
FromLTRB:创建一个具有指定边缘位置的 Rectangle 结构。
GetHashCode:已重写。返回此 Rectangle 结构的哈希代码。有关如何使用哈希代码的信息,请参见 Object.GetHashCode。
Inflate:已重载。创建并返回指定 Rectangle 结构的放大副本。该副本被放大指定的量。
Intersect:已重载。将此 Rectangle 结构替换为其自身与指定 Rectangle 结构的交集。
IntersectsWith:确定此矩形是否与 rect 相交。
Offset:已重载。将此矩形的位置调整指定的量。
Round:通过将 RectangleF 舍入到最近的整数值,将指定的 RectangleF 转换为 Rectangle。
ToString:已重写。将此 Rectangle 的属性转换为可读字符串。
Truncate:通过截断 RectangleF 值,将指定的 RectangleF 转换为 Rectangle。
Union:获取包含两个 Rectangle 结构的交集的 Rectangle 结构。
公共运算符:
相等运算符:测试两个 Rectangle 结构的位置和大小是否相同。
不等运算符:测试两个 Rectangle 结构的位置或大小是否不同。
GraphicsPaths:
这个类表示一系列连接的线条和曲线。在构造一条路径时,可以添加线条、Bezier曲线、圆弧、饼形图、多边形和矩形等。在构造一条复杂的路径后,可以用一个操作绘制路径:调用DrawPath()。可以调用FillPath()填充路径。
使用一个点数组和PathTypes构造GraphicsPath,PathTypes是一个byte数组,其中的每个元素对应于点数组中的每一个元素,并给出了路径如何通过这些点来构造的其他信息。例如,如果点是路径的起始点,那么这个点的路径类型就是PathPointType.Start。如果点是两个线条的连接点,那么这个点的路径类型就是PathPointType.Line。如果点用于构造一条从前一点到后一点之间的Bezier曲线,路经类型就是PathPointType.Bezier。
注意要使用GraphicsPaths需要引入如下命名空间:
using System.Drawing.Drawing2D;
示例,用四条线段创建一个图形路径:
            GraphicsPath path;
            path = new GraphicsPath(new Point[]{
                new Point(10,10),
                new Point(150,10),
                new Point(200,150),
                new Point(10,150),
                new Point(200,160)
                },new byte[]{
      (byte)PathPointType.Start,
                    (byte)PathPointType.Line,
                    (byte)PathPointType.Line,
                    (byte)PathPointType.Line,
                    (byte)PathPointType.Line
                }
            );
            using(Graphics g = this.CreateGraphics())
            {
                g.DrawPath(Pens.Black,path);
            }
Regions:
这个类是一个复杂的图形,由矩形和路径组成。在构造了一个Region后,就可以使用FillRegion()方法绘制该区域。
下面的代码创建了一个区域,给它添加一个Rectangle和一个GraphicsPath,再用蓝色填充该区域:
            Rectangle r1 = new Rectangle(10,10,50,50);
            Rectangle r2 = new Rectangle(40,40,50,50);
            Region r = new Region(r1);
            r.Union(r2);

            GraphicsPath path;
            path = new GraphicsPath(new Point[]{
                new Point(45,45),
                new Point(145,55),
                new Point(200,150),
                new Point(75,150),
                new Point(45,45)
                },new byte[]{
                    (byte)PathPointType.Start,
                    (byte)PathPointType.Bezier,
                    (byte)PathPointType.Bezier,
                    (byte)PathPointType.Bezier,
         (byte)PathPointType.Line
                }
            );
            r.Union(path);
            using(Graphics g = this.CreateGraphics())
            {
                g.FillRegion(Brushes.Blue,r);
            }
颜色:
可以用两种不同的方式来表示,一种是RGB(将红、绿、蓝色值传送给Color结构的一个函数),另一种是把颜色分解为3种组件(色调、饱和度和亮度)。
GetBrightness:获取此 Color 结构的“色调-饱和度-亮度”(HSB) 的亮度值。
GetHue:获取此 Color 结构的“色调-饱和度-亮度”(HSB) 的色调值,以度为单位。
GetSaturation:获取此 Color 结构的“色调-饱和度-亮度”(HSB) 的饱和度值。
GDI+中的颜色还有第4个组件:Alpha组件。使用这个组件可以设置颜色的不透明度,以便创建淡入淡出效果。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值