Transcript chapter10

第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+是如何工作的呢?为了弄清这个问题,让我
们来分析一个示例—绘制一条线段。
 实质上,一条线段是从一个开始位置(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坐标值表示。下图显示的就是坐标的
示意图。
1023,0
A(0,0)
B(250,0)
C(0,250)
D(350,300)
0,767
(1023,767)
坐标的4个相关属性
Left : 表示对象X坐标;
 Top : 表示对象Y坐标;
 Width :表示对象的宽度;
 Height:表示对象的高度;

坐标系中几种属性的示意图
1023,0
A(0,0)
Top
Height
Left
Width
0,767
(1023,767)
10.3绘图对象的介绍
.NET 提供了许多绘图对象,
 在这里我们主要讲解:
 Graphics、Pen、Brush、Font、Color等
GDI+的绘图对象,


通过这些对象,我们可以轻松地进行形状、
文字、线条、图像的处理。
Graphics 对象

Graphics主要是用来建立画布对象的,有
3种基本类型的绘图界面:
 Windows
和屏幕上的控件
 要发送给打印机的页面
 内存中的位图和图像

我们主要讨论的是屏幕上的控件作为绘图界面。
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(); }
}
在Form2中加OK_button, textBox1
把OK_button的DialogResult属性=OK
2)
调用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));
}