1 / 74

第五章 图形图像编程

第五章 图形图像编程. 本章的目的是学习使用 GDI+ 的图形图像编程方法,希望在学习本章以后,能编制像 Windows 画图那样的程序。本章的重点是学习创建画笔、画刷等绘图工具,学习使用 Graphics 类的绘图函数绘制各种图形,学习利用 Bitmap 类处理图形和图像,最后简单介绍多媒体和 3D 图形程序设计的基础知识。. 5.1 GDI+( 图形设备环境接口 ).

konane
Download Presentation

第五章 图形图像编程

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第五章 图形图像编程 本章的目的是学习使用GDI+的图形图像编程方法,希望在学习本章以后,能编制像Windows画图那样的程序。本章的重点是学习创建画笔、画刷等绘图工具,学习使用Graphics类的绘图函数绘制各种图形,学习利用Bitmap类处理图形和图像,最后简单介绍多媒体和3D图形程序设计的基础知识。

  2. 5.1 GDI+(图形设备环境接口) GDI+是2D(2维)图形库,它允许程序员用库中的函数编写与显视器、打印机和文件等图形设备进行交互的Windows和Web应用程序,可以在这些设备上输出字符和2D图形。Windows和Web应用程序根据是在CRT显示还是在打印机打印,首先生成显示设备环境或打印设备环境,然后调用不同设备环境中的同名函数实现在显视器显示或在打印机上打印。而设备环境根据选择的不同设备,调用各个设备制造厂商提供的设备驱动程序,在显视器上显示或在打印机上打印。这些工作都是由GDI+完成的。这样做的最大好处是应用程序和设备无关,应用程序不必为不同的设备编制不同的程序。无论是不同的显卡,还是不同的打印机,只要安装该设备的驱动程序,应用程序就可以使用该设备了,微软的Word程序可以使用不同的打印机就是使用了这个原理。设备环境所扮演的角色如图所示。

  3. CRT 驱动程序 CRT 显示 应 用 程 序 (GDI+) 设 备 环 境 打印机 驱动程序 打印机 打印

  4. GDI+是对Windows操作系统GDI函数库(GDI32.DLL)的扩充,并用C++类进行了封装,GDI+提供了比GDI更强大的功能。WindowsXP及以后版本支持GDI+,以前版本Windows操作系统要使用GDI+,必须复制Gdiplus.dll到系统目录。GDI+支持受控代码和非受控代码。 GDI+是对Windows操作系统GDI函数库(GDI32.DLL)的扩充,并用C++类进行了封装,GDI+提供了比GDI更强大的功能。WindowsXP及以后版本支持GDI+,以前版本Windows操作系统要使用GDI+,必须复制Gdiplus.dll到系统目录。GDI+支持受控代码和非受控代码。

  5. 5.2 Graphics类 Graphics类提供一些方法绘制各种图形。Graphics类是密封类,不能有派生类。

  6. 5.2.1 使用Graphics类绘图的基本步骤 GDI+类提供了一些绘图工具,例如提供笔用来定义图形外轮廓线的颜色及粗细,提供刷子定义添充封闭图形内部的颜色和格式,提供不同输出字体。Graphics类中提供绘图函数使用GDI+类中提供的绘图工具来输出字符或绘制图形。GDI+默认绘图坐标以窗体用户区左上角为原点,x轴向右为正方向,y轴向下为正方向,单位为像素。GDI+定义了三种坐标系统,并提供了三种坐标转换的方法Graphics.TransformPoints()。在不同的控件或设备上绘制图形方法有很大不同,为了在不同的控件或设备上用完全相同的代码完成相同的图形,绘图前应首先建立或得到相应控件或设备关联的Graphics类对象。下面的例子,在窗体中增加了一个按钮,单击按钮将在窗体中画一个边界为红色,内部填充为蓝色的圆。该程序段说明了使用Graphics类绘图的基本步骤。按钮的单击事件处理函数如下:

  7. 绘制矩形定义的园或椭圆,矩形左上角坐标为(10,10),宽和高各为100个像素单位。绘制矩形定义的园或椭圆,矩形左上角坐标为(10,10),宽和高各为100个像素单位。 private void button1_Click(object sender,EventArgs e) { //得到窗体使用的Graphics类对象方法1 Graphics g=this.CreateGraphics(); //创建红色的笔对象 Pen pen1=new Pen(Color.Red); //创建蓝色的刷子对象 SolidBrush brush1=new SolidBrush(Color.Blue); //用红色笔在窗体中画矩形内切圆的边界 g.DrawEllipse(pen1,10,10,100,100); //用蓝色刷子填充矩形内切圆的内部 g.FillEllipse(brush1,10,10,100,100); }

  8. 5.2.2 窗体的Paint事件 运行上例,单击按钮,出现边界为红色,内部填充为蓝色的圆。最小化后再最大化,图形消失。这是因为当发生窗体最小化后再最大化、菜单被打开再关闭或打开对话框再关闭等情况,用户区内容可能被破坏。操作系统不保存被破坏的用户区内容,而是由应用程序自己恢复被破坏的用户区内容。当应用程序窗口用户区内容被破坏后需恢复时,Windows操作系统向应用程序发送Paint事件,应用程序应把在窗口用户区输出数据的语句放在Paint事件处理函数中,应用程序响应Paint事件,能在事件处理函数中调用这些在窗口用户区输出数据的语句恢复被破坏的内容。Form类窗体不能自动响应Paint事件,程序员必须生成Paint事件处理函数。修改上例,在Form1类中增加Paint事件处理函数如下:

  9. private void Form1_Paint(object sender,PaintEventArgs e) { //得到窗体的使用的Graphics类对象方法2,方法3见5.9.4节 Graphics g=e.Graphics; Pen pen1=new Pen(Color.Red); SolidBrush brush1=new SolidBrush(Color.Blue); g.DrawEllipse(pen1,10,10,100,100); g.FillEllipse(brush1,10,10,100,100); } 运行后,出现边界为红色,内部填充蓝色的圆。最小化后,再最大化,图形不消失。

  10. 5.3 GDI+中常用的结构 本节介绍GDI+中常用的结构,包括:Point、PointF、Size、SizeF、Rectangle、RectangleF、Color等。它们是在命名空间System.Drawing中定义的。 点结构Point和PointF定义点的位置。点结构有两个成员:X,Y,表示点的x轴和y轴的坐标。其常用构造函数如下: Point p1=new Point(int X,int Y);//X,Y为整数 PointF p2=new PointF(float X,floa Y);//X,Y为浮点数

  11. 结构Size和SizeF用来描述对象宽和高,有成员Width和Height。常用构造函数如下:结构Size和SizeF用来描述对象宽和高,有成员Width和Height。常用构造函数如下: //坐标系统可以转换,坐标单位可以不是点距 Size(int width,int height); //float类型是为了支持坐标不是点距的单位 //(例如单位为mm) SizeF(float width,float height);

  12. 矩形结构Rectangle和RectangleF用来描述一个矩形,其常用属性和方法如下:矩形结构Rectangle和RectangleF用来描述一个矩形,其常用属性和方法如下: • 属性X、Y和只读属性Left、Top: • 只读属性Right和Bottom: • 属性Width、Height和只读属性Size: • 构造函数Rectangle(Point location,Size size): • 构造函数Rectangle(int X,int Y,int width,int height):

  13. Color结构用来描述颜色。任何一种颜色可以用透明度(alpha),蓝色(bb),绿色(gg),红色(rr)合成,16进制数格式为0xalrrbbgg,其中al,bb,gg,rr为2位16进制数(0-255),用这个无符号32位数代表颜色。Color结构常用方法如下: • public static Color FromArgb (int alpha,int rr,int gg,int bb): • public static Color FromArgb (int rr,int gg,int bb): • public static Color FromArgb (int alpha,Color color): 【例5.1】本例创建3个半透明的红、绿、蓝刷子,填充3个矩形,请注意例子中透明度及颜色使用的方法。

  14. private void Form1_Paint (object sender,PaintEventArgs e) { Graphics g=e.Graphics; SolidBrush RedBrush=new SolidBrush (Color.FromArgb(128,255,0,0)); //半透明 SolidBrush GreenBrush=new SolidBrush(Color.FromArgb(128,0,255,0)); SolidBrush BlueBrush=new SolidBrush(Color.FromArgb(128,0,0,255)); g.FillRectangle(RedBrush,0,0,80,80); g.FillRectangle(GreenBrush,40,0,80,80); g.FillRectangle(BlueBrush,20,20,80,80); }

  15. 效果如图,可以将透明度alpha值设为255,再运行一次,看看有何不同。C#中还预定义了一些颜色常数,例如黑色为Color.Black,红色为Color.Red等等,请用VS2005帮助系统查看。效果如图,可以将透明度alpha值设为255,再运行一次,看看有何不同。C#中还预定义了一些颜色常数,例如黑色为Color.Black,红色为Color.Red等等,请用VS2005帮助系统查看。

  16. 5.4 画笔Pen类 Pen类对象指定绘制图形的外轮廓线宽度和颜色。Pen类有4个构造函数,分别是: • public Pen(Color color); • public Pen(Color color,float width); • public Pen(Brush brush); • public Pen(Brush,float width); 【例5.2】Pen类常用的属性:Color为笔的颜色,Width为笔的宽度,DashStyle为笔的样式,EndCap和StartCap为线段终点和起点的外观。下例显示各种笔的属性DashStyle、EndCap和StartCap不同选项的样式。主窗体Paint事件处理函数如下,运行效果如图。

  17. private void Form1_Paint(object sender,PaintEventArgs e) { Graphics g=e.Graphics; Pen pen1=new Pen(Color.Red,6); //默认为实线笔 //从点(10,10)到点(100,100)的实线,图中左边第1条线 g.DrawLine(pen1,10,10,100,10); pen1.DashStyle= System.Drawing.Drawing2D.DashStyle.Dash; //虚线笔 g.DrawLine(pen1,10,20,100,20);//画虚线图中左边第2条线 //点短线风格的线 pen1.DashStyle= System.Drawing.Drawing2D.DashStyle.DashDot; g.DrawLine(pen1,10,30,100,30); //图中左边第3条线 //下条语句设置双点,短线风格的线风格 pen1.DashStyle= System.Drawing.Drawing2D.DashStyle.DashDotDot; g.DrawLine(pen1,10,40,100,40); //图中左边第4条线

  18. pen1.DashStyle= //由点组成的线 System.Drawing.Drawing2D.DashStyle.Dot; g.DrawLine(pen1,10,50,100,50);//图中左边第5条线 pen1.DashStyle= //恢复实线笔 System.Drawing.Drawing2D.DashStyle.Solid; pen1.EndCap= //后箭头 System.Drawing.Drawing2D.LineCap.ArrowAnchor; g.DrawLine(pen1,150,10,250,10);//图中右边第1条线 pen1.StartCap= //前箭头 System.Drawing.Drawing2D.LineCap.ArrowAnchor; g.DrawLine(pen1,150,22,250,22); //图中右边第2条线 pen1.EndCap= System.Drawing.Drawing2D.LineCap.RoundAnchor; g.DrawLine(pen1,150,34,250,34); //图中右边第3条线

  19. pen1.EndCap= System.Drawing.Drawing2D.LineCap.SquareAnchor; g.DrawLine(pen1,150,46,250,46); //图中右边第4条线 pen1.EndCap=System.Drawing.Drawing2D.LineCap.Triangle; g.DrawLine(pen1,150,58,250,58); //图中右边第5条线 pen1.EndCap= System.Drawing.Drawing2D.LineCap.DiamondAnchor; g.DrawLine(pen1,150,70,250,70); //图中右边第6条线 }

  20. 5.5 创建画刷 画刷类对象指定填充封闭图形内部的颜色和样式,封闭图形包括矩形、椭圆、扇形、多边形和任意封闭图形。GDI+系统提供了几个预定义画刷类,包括: • SolidBrush:单色画刷,在命名空间System.Drawing中定义。 • HatchBrush:阴影画刷,后4个画刷在命名空间System.Drawing.Drawing2D中定义。 • TextureBrush:纹理(图像)画刷。 • LinearGradientBrush:两个颜色或多个颜色线性渐变画刷。 • PathGradientBrush:使用路径定义刷子形状的复杂渐变画刷。

  21. 5.5.1 单色画刷SolidBrush 前边已使用过单色画刷。其构造函数只有1个,定义如下: //建立指定颜色的画刷 SolidBrush brush1=new SolidBrush(Color color); 可以使用属性Color来修改画刷颜色,例如:brush1.Color=Color.Green;

  22. 5.5.2 阴影画刷HatchBrush 阴影画刷是指定样式(例如,多条横线、多条竖线、多条斜线等)、指定填充线条的颜色和指定背景颜色的画刷,阴影画刷常用属性和方法如下: • 属性backgroundColor:画刷背景颜色。 • 属性foreColor:画刷填充线条的颜色。 • 属性HatchStyle:该属性是只读的,不能修改,表示画刷的不同样式。 • 构造函数HatchBrush(HatchStyle h,Color c):参数1指定样式,参数2指定填充线条的颜色,背景色被初始化为黑色。 • 构造函数HatchBrush(HatchStyle h,Color c1,Color c2):参数1指定样式,参数2指定填充线条的颜色,参数3指定背景色。

  23. 【例5.3】例子显示了属性HatchStyle为不同值时阴影画刷的不同样式。在Form1.cs文件头部增加语句using System.Drawing.Drawing2D,窗体Paint事件处理函数如下: private void Form1_Paint(object sender,PaintEventArgs e) { Graphics g=e.Graphics; //得到窗体使用的Graphics类对象 HatchBrush b1=new HatchBrush(HatchStyle.BackwardDiagonal, Color.Blue,Color.LightGray); //矩形被填充左斜线,下图窗体中第1图 g.FillRectangle(b1,10,10,50,50); HatchBrush b2=new HatchBrush (HatchStyle.Cross,Color.Blue,Color.LightGray); g.FillRectangle(b2,70,10,50,50);//矩形被填充方格,第2图 HatchBrush b2=new HatchBrush(HatchStyle.Cross, Color.Blue,Color.LightGray);

  24. g.FillRectangle(b2,70,10,50,50);//矩形被填充方格,第2图g.FillRectangle(b2,70,10,50,50);//矩形被填充方格,第2图 HatchBrush b3=new HatchBrush(HatchStyle.ForwardDiagonal, Color.Blue,Color.LightGray); g.FillRectangle(b3,130,10,50,50);//矩形被填充右斜线,第3图 HatchBrush b4=new HatchBrush(HatchStyle.DiagonalCross, Color.Blue,Color.LightGray); g.FillRectangle(b4,190,10,50,50);//矩形被填充菱形,第4图 HatchBrush b5=new HatchBrush(HatchStyle.Vertical, Color.Blue,Color.LightGray); g.FillRectangle(b5,250,10,50,50);//矩形被填充竖线,第5图 HatchBrush b6=new HatchBrush(HatchStyle.Horizontal, Color.Blue,Color.LightGray); g.FillRectangle(b6,310,10,50,50);//矩形被填充横线,第6图 } //运行效果如图

  25. 5.5.3 纹理(图像)画刷TextureBrush 纹理(图像)画刷使用图像填充封闭曲线的内部,有8个构造函数,最简单的构造函数如下,参数为画刷使用的位图类对象,其余请读者使用MSDN或VS2005帮助系统查看。TextureBrush(Image bitmap); 【例5.4】例子使用位图文件n2k.bmp建立位图类对象作为画刷的图案,在Form1.cs文件的头部增加语句using System.Drawing.Drawing2D,窗体Paint事件处理函数如下: n2k.bmp是Windows2000操作系统中的一个位图文件,应用程序运行效果如图。

  26. private void Form1_Paint(object sender,PaintEventArgs e) { Graphics g=e.Graphics;//得到窗体使用的Graphics类对象 Pen pen1=new Pen(Color.Red); //建立位图类对象见5.10节 Bitmap b1=new Bitmap("C:\\WINNT\\system32\\n2k.bmp"); TextureBrush b1=new TextureBrush(b1); g.FillRectangle(b1,10,10,200,100); g.DrawRectangle(pen1,10,10,200,100); }

  27. 5.5.4颜色渐变画刷LinearGradientBrush 5.5.5画刷PathGradientBrush和GraphicsPath类 自学

  28. 5.6 基本图形的绘制和填充 Graphics类提供了一些方法,用来绘制或填充各种图形。本节介绍这些方法。

  29. 5.6.1 用DrawLine方法绘制线段 绘制线段方法定义如下: • void DrawLine(Pen pen,int x1,int y1,int x2,int y2): • DrawLine(Pen pen,Point p1,Point p2): • public void DrawLines(Pen pen,Point[] points): 【例5.7】使用DrawLine()的例子,为主窗体Paint事件增加事件处理函数如下:

  30. private void Form1_Paint (object sender,PaintEventArgs e) { Graphics g=e.Graphics; Pen pen1=new Pen(Color.Red); //用笔pen1从点(30,30)到(100,100)画直线 g.DrawLine(pen1,30,30,100,100); Point p1=new Point(30,40); Point p2=new Point(100,110); //用笔pen1从点(30,40)到(100,110)画直线 g.DrawLine(pen1,p1,p2); }

  31. 【例5.8】使用绘制线段函数画任意曲线(画正弦曲线,注意如何使用数学函数)。【例5.8】使用绘制线段函数画任意曲线(画正弦曲线,注意如何使用数学函数)。 private void Form1_Paint(object sender,PaintEventArgs e) { //得到窗体的使用的Graphics类对象 Graphics g=this.CreateGraphics(); Pen pen1=new Pen(Color.Red); float y=50,y1,x1,x2; for(int x=0;x<720;x++) //画2个周期正弦曲线 { x1=(float)x; x2=(float)(x+1); y1=(float)(50+50*Math.Sin((3.14159/180.0)*(x+1))); g.DrawLine(pen1,x1,y,x2,y1); y=y1; } } //运行,在窗体中可以看到一条红色正弦曲线如图

  32. 【例5.9】在Windows画图程序中,可以拖动鼠标画任意曲线。本例实现用拖动鼠标左键在主窗体中画曲线。每条曲线都是由若干很短的线段组成。鼠标左键在按下状态,移动鼠标,每次移动很短距离,画出这段线段,所有这些线段组合起来,形成一条曲线。【例5.9】在Windows画图程序中,可以拖动鼠标画任意曲线。本例实现用拖动鼠标左键在主窗体中画曲线。每条曲线都是由若干很短的线段组成。鼠标左键在按下状态,移动鼠标,每次移动很短距离,画出这段线段,所有这些线段组合起来,形成一条曲线。 • 新建项目。在Form1类中增加两个私有变量: //表示鼠标左键是否按下,如按下鼠标再移动将画曲线 private bool mark=false; //记录画下一条很短线段的起始点 private Point point; • 为主窗体的事件OnMouseDown,OnMouseUp,OnMouseMove增加事件处理函数如下:

  33. private void Form1_MouseDown (object sender,MouseEventArgs e) { if(e.Button==MouseButtons.Left) //如果鼠标左键按下 { //记录曲线的第一个点的坐标,为画线段的起始点 point.X=e.X; point.Y=e.Y; mark=true;//表示鼠标左键已按下,鼠标如果再移动,将画曲线 } } private void Form1_MouseMove (object sender,MouseEventArgs e) { if(mark) //如果鼠标左键已按下 { //得到窗体的使用的Graphics类对象 Graphics g=this.CreateGraphics();

  34. Pen pen1=new Pen(Color.Black); //黑笔 //画线注意画线起始点和终点 g.DrawLine(pen1,point.X,point.Y,e.X,e.Y); point.X=e.X; //记录画下一线段的起始点的坐标 point.Y=e.Y; } } private void Form1_MouseUp (object sender,MouseEventArgs e) { mark=false; } //表示鼠标移动不再画线 • 运行,在主窗体中拖动鼠标左键可以画线。但最小化后再最大化后,图形消失。

  35. 现修改上例,使其克服这个缺点。实现的思路是记录每一条曲线的每一条很短线段的坐标。使用List类对象记录曲线以及曲线中的点,请注意List类使用方法。现修改上例,使其克服这个缺点。实现的思路是记录每一条曲线的每一条很短线段的坐标。使用List类对象记录曲线以及曲线中的点,请注意List类使用方法。 • 在定义主窗体的Form1类中增加私有变量: //用来记录1条曲线的所有点。 private List<Point> Point_List; //用来记录每条曲线,既Point_List Private List<List<Point>> Line_List; • 在Form1类构造函数中增加语句:Line_List = new List<List<Point>>(); • 修改主窗体事件OnMouseDown,OnMouseUp,OnMouseMove事件处理函数如下:

  36. private void Form1_MouseDown (object sender,MouseEventArgs e) { if(e.Button==MouseButtons.Left) { //建立数组,记录1条曲线的所有点 Point_List=new List<Point>(); point.X=e.X; point.Y=e.Y; mark=true; Point_List.Add(point);//记录曲线起点的坐标 } }

  37. private void Form1_MouseMove (object sender,MouseEventArgs e) { if(mark) { Graphics g=this.CreateGraphics(); Pen pen1=new Pen(Color.Black); g.DrawLine(pen1,point.X,point.Y,e.X,e.Y); point.X=e.X; point.Y=e.Y; Point_List.Add(point); //记录曲线中其他点的坐标 } } private void Form1_MouseUp (object sender,MouseEventArgs e) { mark=false; //记录此条线,注意参数是Point_List Line_List.Add(Point_List); }

  38. 增加主窗体的Paint事件处理函数如下,该函数重画记录的所有曲线。增加主窗体的Paint事件处理函数如下,该函数重画记录的所有曲线。 private void Form1_Paint (object sender,PaintEventArgs e) { Graphics g=e.Graphics; Pen pen1=new Pen(Color.Black); Point p1,p2; foreach (List<Point> l in Line_List)//取出每条线 { for(int k=0;k<(l.Count-1);k++)//重画每条线的点 { p1= l[k]; p2= l[k+1]; g.DrawLine(pen1,p1,p2); } } //运行,在Form窗体拖动鼠标可以画线。 } //最小化后再最大化后,图形不消失。

  39. 5.6.2 泛型List类 在C#2.0中程序中可用泛型List 类替换 C#1.x中的ArrayList 类,List 类在大多数情况下比ArrayList 类性能更好并且类型安全。List类是容量可以动态增加的数组,其元素可以是任意类型,但在使用前必须指定具体的数据类型。List类可以使用对象名[索引号]引用其元素,索引号从零开始。常用属性及方法如下: • 属性Count:List中实际包含的元素数。 • 方法Add:将参数指定的对象添加到List对象的结尾处。 • 方法Clear:从List中移除所有元素。 • 方法Contains:bool类型,确定参数指定的元素是否在List中。

  40. 方法IndexOf:int类型,顺序查找和参数指定对象相同的第一个元素的索引。方法IndexOf:int类型,顺序查找和参数指定对象相同的第一个元素的索引。 • 方法Insert:插入数据,第1个参数为插入的位置(索引号),第2个参数为插入的对象。 • 方法LastIndexOf:顺序查找和参数指定对象相同的最后一个元素的索引。 • 方法RemoveAt:移除参数指定索引处的元素。 • 方法Sort:对整个List中的元素进行排序。

  41. 5.6.3 DrawEllipse方法画椭圆(圆)及键盘事件 画椭圆的两个方法如下,功能是画指定矩形的内切椭圆,如指定正方形则画圆。 • void DrawEllipse(Pen pen,int x,int y,int width,int height):pen为画笔,画椭圆的边,(x,y)为矩形的左上角坐标,width为矩形的宽,height为矩形的高。 • void DrawEllipse(Pen pen,Rectangle r):pen为画笔,画椭圆的边,r为矩形结构。 【例5.10】画椭圆。为主窗体Paint事件增加事件处理函数如下:

  42. private void Form1_Paint (object sender,PaintEventArgs e) { Graphics g=this.CreateGraphics(); Pen pen1=new Pen(Color.Red); g.DrawEllipse(pen1,10,10,200,100); Rectangle rect=new Rectangle(20,20,100,100); g.DrawEllipse(pen1,rect); }

  43. 【例5.11】用键盘的四个箭头键移动窗体中的圆。移动圆,实际是先把前边画的圆擦掉,在新的位置重新画圆。如要擦除圆,可以用窗体背景色作为笔和刷子的颜色,在要擦除的圆的位置重画和填充圆。注意键盘事件处理函数的使用。具体实现步骤如下:【例5.11】用键盘的四个箭头键移动窗体中的圆。移动圆,实际是先把前边画的圆擦掉,在新的位置重新画圆。如要擦除圆,可以用窗体背景色作为笔和刷子的颜色,在要擦除的圆的位置重画和填充圆。注意键盘事件处理函数的使用。具体实现步骤如下: • 新建项目。在Form1类中增加变量:int x,y,记录定义圆位置的矩形左上角的坐标。 • 在Form1类中增加一个方法,该方法按照参数指定颜色画圆,方法定义如下: void DrawCir(Color color)//参数是画圆的笔和刷子的颜色 { Graphics g=this.CreateGraphics(); Pen pen1=new Pen(color); SolidBrush brush1=new SolidBrush(color); g.DrawEllipse(pen1,x,y,100,100); g.FillEllipse(brush1,x,y,100,100); }

  44. 为主窗体Paint事件增加事件处理函数如下: private void Form1_Paint (object sender,PaintEventArgs e) { DrawCir(Color.Red); } • 为主窗体KeyDown事件增加事件函数如下:(注意不要使用KeyPress事件,其事件处理函数的第2个参数e的e.KeyChar是按下键的ASCII值,但很多键无ASCII值。) private void Form1_KeyDown(object sender,KeyEventArgs e) { switch (e.KeyCode) //e.KeyCode是键盘每个键的编号 { case Keys.Left: //Keys.Left是左箭头键编号 DrawCir(this.BackColor);//用主窗体的背景色画圆,即擦除圆 x=x-10; //圆左移 DrawCir(Color.Red);//在新的位置用红色画圆,效果是圆左移 break; case Keys.Right: //圆右移 DrawCir(this.BackColor);

  45. x+=10; DrawCir(Color.Red); break; case Keys.Down: //圆下移 DrawCir(this.BackColor); y+=10; DrawCir(Color.Red); break; case Keys.Up: //圆上移 DrawCir(this.BackColor); y=y-10; DrawCir(Color.Red); break; } }

  46. 运行,可以用4个箭头键移动红色圆。键盘KeyDown事件处理函数的第2个参数e的e.KeyCode是被按下键的编号,常用键的编号如下:数字键0-9编号为Keys.D0-Keys.D9;字母键A-Z为Keys.A-Keys.Z;F0-F12键表示为Keys.F0-Keys.F12等。键盘KeyPress事件处理函数的第2个参数e的e.KeyChar表示被按下键的ACSII值,例如可用如下语句if(e.KeyChar==(char)13)判断是否按了回车键。运行,可以用4个箭头键移动红色圆。键盘KeyDown事件处理函数的第2个参数e的e.KeyCode是被按下键的编号,常用键的编号如下:数字键0-9编号为Keys.D0-Keys.D9;字母键A-Z为Keys.A-Keys.Z;F0-F12键表示为Keys.F0-Keys.F12等。键盘KeyPress事件处理函数的第2个参数e的e.KeyChar表示被按下键的ACSII值,例如可用如下语句if(e.KeyChar==(char)13)判断是否按了回车键。

More Related