380 likes | 640 Views
第 10 章 GDI+ 绘图. 3 hours. 主要内容. GDI+ 中的颜色和坐标 GDI+ 中的绘图对象 GDI 是 Graphics Device Interface 的缩写, 是图形设备接口, 它的主要任务是负责系统与绘图程序之间的信息交换,处理所有 Windows 程序的图形输出。. 10.1 GDI+ 简介. GDI+ 是由 GDI 技术“进化”而来,并添加了新的功能。 GDI+ 是 Windows 中的一个子系统,它负责在屏幕和打印设备输出有关信息,它是一组通过 C++ 类实现的应用程序编程接口。
E N D
第10章 GDI+绘图 3 hours
主要内容 • GDI+中的颜色和坐标 • GDI+中的绘图对象 GDI是Graphics Device Interface的缩写, 是图形设备接口, 它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。
10.1 GDI+简介 • GDI+是由GDI技术“进化”而来,并添加了新的功能。 • GDI+是Windows 中的一个子系统,它负责在屏幕和打印设备输出有关信息,它是一组通过C++ 类实现的应用程序编程接口。 • 无需考虑具体显示设备的细节, 只需调用GDI+库输出的类的一些方法即可完成图形操作,真正的绘图工作由这些方法交给特定的设备驱动程序来完成. • GDI+使得图形硬件和应用程序相互隔离,从而使开发人员编写设备无关的应用程序变得非常容易。
GDI+新增功能的介绍 • 1.渐变的画刷(Gradient Brushes) • GDI+允许用户创建一个沿路径或直线渐变的画刷,来填充外形(shapes),路径(paths),区域(regions),渐变画刷同样也可以画直线、曲线、路径,当你用一个线形画刷填充一个外形(shapes)时,颜色就能够沿外形逐渐变化。 • 2.基数样条函数(Cardinal Splines) • GDI+支持基数样条函数,而GDI不支持。基数样条是一组单个曲线按照一定的顺序连接而成的一条较大曲线。样条由一系列点指定,并通过每一个指定的点。由于基数样条平滑地穿过组中的每一个点(不出现尖角),因而它比用直线连接创建的路径更精确。
GDI+新增功能的介绍 • 3.持久路径对象(Persistent Path Objects) • 在GDI中,路径属于设备描述表(DC),画完后路径就会被破坏。在GDI+中,绘图工作由Graphics对象来完成,你可以创建几个与Graphics分开的路径对象,绘图操作时路径对象不被破环,这样你就可以多次使用同一个路径对象画路径了。 • 4.变形和矩阵对象(Transformations & Matrix Object) • GDI+提供了矩阵对象,使得编写图形的旋转、平移、缩放代码变得非常容易。一个矩阵对象总是和一个图形变换对象联系起来。
GDI+新增功能的介绍 5.多种图像格式支持 • GDI+除了支持BMP等GDI支持的图形格式外,还支持JPEG、GIF、PNG、TIFF等图像格式,你可以直接在程序中使用这些图片文件,而无需考虑它们所用压缩算法。 6.其他 • GDI+还将支持其他技术,譬如重新着色、颜色校正、元数据、图形容器。
GDI+的工作机理 • GDI+为开发者提供了一组实现与各种设备进行交互的库函数。 • GDI+的本质在于,它能够替代开发人员实现与显示器及其他外设的交互;而从开发者角度来看,要实现与这些设备的直接交互却是一项艰巨的任务。
下图展示了GDI+在开发人员与上述设备之间起着重要的中介作用。其中,GDI+为我们“包办”了几乎一切——从把一个简单的字符串“HelloWorld”打印到控制台到绘制直线、矩形甚至是打印一个完整的表单等。下图展示了GDI+在开发人员与上述设备之间起着重要的中介作用。其中,GDI+为我们“包办”了几乎一切——从把一个简单的字符串“HelloWorld”打印到控制台到绘制直线、矩形甚至是打印一个完整的表单等。
GDI+工作原理 • GDI+是如何工作的呢?为了弄清这个问题,让我们来分析一个示例—绘制一条线段。 • 实质上,一条线段是从一个开始位置(X0,Y0)到一个结束位置(Xn,Yn)的一系列像素点的集合。为了画出这样的一条线段,设备需要知道相应的设备坐标或物理坐标。 • 然而,开发人员不是直接告诉该设备,而是调用GDI+的DrawLine()方法,然后,由GDI+在内存(即“视频内存”)中绘制一条从点A到点B的直线。GDI+读取点A和点B的位置,然后把它们转换成一个像素序列,并且指令监视器显示该像素序列。简言之,GDI+把设备独立的调用转换成了一个设备可理解的形式。
10.2颜色与坐标 • 颜色与坐标是GDI+中2个核心的东西; 颜色用于表达所绘制图形的外观; 坐标用于表达所绘制图形的位置;
GDI+的颜色设置 • GDI+中,很多绘图操作都要涉及颜色的问题,举个例子,要绘制一个矩形,就要指定其边框的颜色以及其内部的填充色,当然,我们可以使用GDI+的默认颜色。 • GDI+中,颜色都封装在Color结构中。把红、绿、蓝色值传送给Color结构的一个函数,就可以创建一种颜色。
设置颜色的几种方法 • 使用Color对象的方法来设置颜色 • 使用ColorTranslator对象的方法来设置颜色 • 使用Color结构来设置颜色
使用Color的方法来设置颜色 • Color类的方法有FromArgb()以及FromKnownColor() private void button1_Click(object sender, EventArgs e) • { • button1.ForeColor =Color.FromArgb(255, 0, 0); //Red • button1.BackColor = • Color.FromKnownColor(KnownColor.Blue); //Blue • }
程序运行结果解析 • FromArgb()方法中的(Red,Green,Blue)三个参数,分别代表红、绿、蓝颜色光的亮度,每个颜色值分别从0至255分成256个亮度等级,数值越大,表示该颜色光越亮。 例如: RGB(255,0,0)为红色, RGB(0,255,0)为绿色, RGB(0,0,255)为蓝色, RGB(255,0,255)为紫色(红+蓝)。 所以,此程序运行的最终结果是button1的前景色改为红色,背景色修改为蓝色,如 图所示。
使用Color结构来设置颜色 • .NET结构中本身就带有Color结构,其中定义了许多常用的Color颜色名称,我们可以直接调用,就可以指定颜色了。 • 下面这行代码表示把button1的前景值设为红色: button1.ForeColor = Color.Red;
GDI+中的坐标空间 • GDI+为我们提供了三种坐标空间: • 世界坐标系 • 页面坐标系 • 设备坐标系。
世界坐标系 • “世界坐标系”是应用程序用来进行图形输入输出所使用的一种与设备无关的笛卡尔坐标系。 • 通常,我们可以根据自己的需要和方便定义一个自己的世界坐标系,这个坐标系称为用户坐标系,默认时使用像素为单位。
设备坐标系 • “设备坐标系”是指显示设备或打印设备坐标系下的坐标,它的特点是以设备上的像素点为单位。 • 对于窗口中的视图而言,设备坐标的原点在客户区的左上角,x坐标从左向右递增,y坐标自上而下递增。 • 由于设备的分辨率不同,相同坐标值的物理位置可能不同。如对于边长为100的正方形,当显示器为640 x 480和800 x 600时的大小是不一样的。
页面坐标系 • “页面坐标系”是指某种映射模式下的一种坐标系。所谓映射是指将世界坐标系通过某种方式进行的变换。 • 默认时,设备坐标和页面坐标是一致的。
坐标的示意图 • 在实际的绘图中,我们所关注的一般都是指设备坐标系,此坐标系以像素为单位,像素指的是屏幕上的亮点。 • 每个像素都有一个坐标点与之对应,左上角的坐标设为(0,0),向右为正,向下为正。一般情况下以(x,y)代表对象上某个像素的坐标点,其中水平以X坐标值表示,垂直以Y坐标值表示。下图显示的就是坐标的示意图。
坐标的4个相关属性 • Left : 表示对象X坐标; • Top : 表示对象Y坐标; • Width :表示对象的宽度; • Height:表示对象的高度;
10.3绘图对象的介绍 • .NET 提供了许多绘图对象, • 在这里我们主要讲解: • Graphics、Pen、Brush、Font、Color等GDI+的绘图对象, • 通过这些对象,我们可以轻松地进行形状、文字、线条、图像的处理。
Graphics 对象 • Graphics主要是用来建立画布对象的,有3种基本类型的绘图界面: • Windows 和屏幕上的控件 • 要发送给打印机的页面 • 内存中的位图和图像
我们主要讨论的是屏幕上的控件作为绘图界面。Graphics对象的创建语法为:我们主要讨论的是屏幕上的控件作为绘图界面。Graphics对象的创建语法为: Graphics g=控件对象名称.CreateGraphics(); • 比如说,分别以一个Button控件和Label控件作为绘图界面,那么创建Graphics对象的语句为: Graphics g1=button1.CreateGraphics(); Graphics g2=label1.CreateGraphics();
Pen对象 • Pen是笔类,是在Graphics对象上绘制图形。使用的语法为: Pen p = new Pen(Color.Blue, 2); Pen 的构造函数可建立画笔的颜色以及线条的宽度,如上。 • 在定义好Pen对象以后,我们还可以对其进行修改,如: p.Color = Color.Red; p.Width = 3; • 此外,System.Drawing.Pens类中储备好了很多预先设好的笔,我们可以直接调用,缺点是这些钢笔的宽度都是1个像素。我们就可以直接这样简单地构造一个笔对象: • Pen p1 = Pens.Yellow;
Brush 对象 • Brush对象是画笔类,用来绘制实心、渐变的图形,使得图案显得比较有质感。 • 每种画笔都由一个派生于System.Drawing.Brush的类的实例来表示,这个类是个抽象类,所以不能实例化该类的对象。 • 最简单的画笔仅指定了区域用纯色来填充。这种画笔由System.Drawing.Brush类的实例表示,该实例可以如下构造: • Brush b = new SolidBrush(Color.Orange);
复杂的画笔 • 比较复杂的画笔对象有好多种,主要有 : • HatchBrush • LinearGradientBrush • PathGradientBrush • SolidBrush • 这些画笔包含在System.Drawing.Drawing2D命名空间中,所以要在程序的开头添加对System.Drawing.Drawing2D的引用,才可以比较便捷地建立Brush类。
HatchBrush • HatchBrush对象是影像画笔,它通过绘制一种模式来填充区域,其基本语法为: HatchBrush hb = new HatchBrush(HatchStyle, ForeColor, BackColor); • HatchStyle 指的是在画布上绘制的图案,ForeColor指的是绘图的前景色,BackColor指的是绘图的背景色,所以当我们需要绘制一个前景色为橙色、背景色为蓝色,图案花纹为交叉的水平线和垂直线时,就可以这样定义画笔: HatchBrush hb = new HatchBrush(HatchStyle.Cross, Color.Orange, Color.Blue);
winPaint (Do it!) using System.Drawing; namespace winPaint { public partial class Form1 : Form { void myPaint() { Graphics g = CreateGraphics(); Pen pen = Pens.Red; Rectangle rect = new Rectangle(10, 10, 30, 30); Rectangle rect2 = new Rectangle(30, 30, 50, 50);
winPaint (Do it!) Point[] ps= new Point[3]; ps[0].X=10; ps[0].Y=10; ps[1].X=10; ps[1].Y=100; ps[2].X=300; ps[2].Y=200; g.DrawLine(pen, 0, 0, 100, 200); g.DrawEllipse(pen, rect); g.DrawLines(Pens.SpringGreen, ps); g.FillRectangle(Brushes.Blue, rect2); g.Dispose();
Paint事件的函数《==》 OnDraw() private void Form1_Paint(object sender, PaintEventArgs e) { myPaint(); }
小结 • 本章主要介绍了System.Drawing 名称空间中的一些类,讨论了颜色的设置以及GDI+中的坐标的分类,还讨论GDI+ 中的几种绘图对象,详细介绍了绘图机制,在窗口需要重新绘制时,就应调用Paint事件的响应函数。 • GDI+是Window XP中的一个子系统,它主要负责在显示屏幕和打印设备输出有关信息,它是一组通过C++ 类实现的应用程序编程接口。 • Pen是钢笔对象,主要功能是在Graphics对象上绘制图形。Pen 对象的构造函数可建立画笔的颜色以及线条的宽度。 • Brush对象是画笔对象,用来绘制实心、渐层的图形,使得图案显得比较有质感。每种画笔都由一个派生于System.Drawing.Brush的类的实例来表示,由于这个类是个抽象类,所以不能实例化派生类的对象。最简单的画笔仅指定了区域用纯色来填充。
2 对话框也是Form.(中WinPaint, do it) 1)在Form1中, 用【项目/添加Windows窗体】--- 添加 Form2 public partial class Form2 : Form { public Form2() { InitializeComponent(); } } 2)在Form2中加OK_button, textBox1 把OK_button的DialogResult属性=OK
调用Form2对话框 3)在Form1的button1中调用Form2: private void button1_Click(object sender, EventArgs e) { string st; Form2 dlg = new Form2(); if (DialogResult.OK == dlg.ShowDialog()) st = dlg.text; }
调用image(do it) 1) button2_Click(object sender, EventArgs e) { ImageDraw = true; Invalidate(true); } 2) private void Form1_Paint(object sender, PaintEventArgs e) { if (ImageDraw) PaintImage(e); }
调用image void PaintImage(PaintEventArgs e) { Image myimg = Image.FromFile(@"c:\lily.jpg"); Graphics g = e.Graphics; g.DrawImage(myimg, new PointF(0.0F, 0.0F)); }