当前位置:首页 > C#WinForm编程(3).第33章使用GDI+绘图
Pen bluePen = new Pen(Color.Blue, 3); Point topLeft = new Point(0,0); Size howBig = new Size(50,50); Rectangle rectangleArea = new Rectangle(topLeft, howBig); dc.DrawRectangle(bluePen, rectangleArea); 这段代码也使用Graphics.DrawRectangle()的另一个重载方法,它的参数是Pen和 Rectangle结构。 通过按顺序提供矩形的左上角水平和垂直坐标,宽度和高度(它们都是数字),可以构造一个Rectangle: Rectangle rectangleArea = new Rectangle(0, 0, 50, 50) Rectangle包含几个读写属性,如表33-3所示,可以用不同的属性组合来设置或提取它的维数。 表 33-3 属 性 int Left int Right int Top int Bottom int X int Y int Width int Height Point Location Size Size 说 明 左边界的x坐标 右边界的x坐标 顶边的y坐标 底边的y坐标 与 Left相同 与Top相同 矩形的宽度 矩形的高度 左上角 矩形的大小 注意,这些属性都不是独立的,例如,设置Width会影响Right的值。 33.2.4 Region Region表示屏幕上一个有复杂图形的区域。例如,图33-5中的阴影区域就可以用Region表示。 可以想象,初始化Region实例的过程相当复杂。从广义上看,可以指定哪些简单的图形组成这个区域,或指定绘制这个区域边界的路径。如果需要处理这样的区域,就应掌握SDK文档中的Region类。 图 33-5 33.3 调试须知 下面准备进行一些更高级的绘图工作。但首先介绍几个调试问题。如果在本章的示例中设置了断点,就会注意到调试图形例程不像调试其他程序那样简单。这是因为进入和退出调试程序常常会把Paint信息传送给应用程序。结果是在OnPaint重载方法上设置的断点会让应用程序一遍又一遍地绘制它本身,这样应用程序就不能完成任何工作。 这是很典型的一种情形。要明白为什么应用程序没有正确显示,可以在OnPaint上设置断点。应用程序会像期望的那样,遇到断点后,就会进入调试程序,此时在前景上会显示开发环境MDI窗口。如果把开发环境设置为满屏显示,以便更易于观察所有的调试信息,就会完全隐藏目前正在调试的应用程序。 接着,检查某些变量的值,希望找出某些有用的信息。然后按下F5,告诉应用程序继续执行,完成某些处理后,看看应用程序在显示其他内容时会发生什么。但首先发生的是应用程序显示在前景中,Windows检测到窗体再次可见,并提示给它发送了一个Paint事件。当然这表示程序遇到了断点。如果这就是我们希望的结果,那就很好。但更常见的是,我们希望以后在应用程序绘制了某些有趣的内容后再遇到断点,例如在选择某些菜单项,读取一个文件或者以其他方式改变显示的内容之后再遇到断点。这听起来就是我们需要的结果。我们根本没有在OnPaint中设置断点,应用程序也不会显示它在最初的启动窗口中显示的内容之外的其他内容。 有一种方式可以解决这个问题。如果有足够大的屏幕,最简单的方式就是平铺开发环境窗口,而不是把它设置为最大化,使之远离应用程序窗口,这样应用程序就不会被挡住了。但在大多数情况下,这并不是一个有效的解决方案,因为这样会使开发环境窗口过小(也可以使用第二个监视器)。另一个解决方案使用相同的规则,即把应用程序声明为在调试时放在最上层。方法是在Form类中设置属性TopMost,这很容易在InitializeComponent方法中完成: private void InitializeComponent() { this.TopMost = true; 也可以在Visual Studio 2008的属性窗口中设置这个属性。
窗口设置为TopMost表示应用程序不会被其他窗口挡住(除了其他放在最上层的窗口)。它总是放在其他窗口的上面,甚至在另一个应用程序得到焦点时,也是这样。这是任务管理器的执行方式。
利用这个技巧时必须小心,因为我们不能确定Windows何时会决定应为某种原因引发Paint事件。如果在某些特殊的情况下,OnPaint出了问题(例如,应用程序在选择某个菜单
项后绘图,但此时出了问题)。最好的方式是在OnPaint中编写一些虚拟代码,测试某些条件,这些条件只在特殊的情况下才为true。然后在if块中设置断点,如下所示。 protected override void OnPaint( PaintEventArgs e ) { // Condition() evaluates to true when we want to break if ( Condition() == true) { int ii = 0; // <-- SET BREAKPOINT HERE!!! } 上面的这段代码是设置条件断点的一种简捷方式。 33.4 绘制可滚动的窗口 前面的DrawShapes示例运行良好,因为需要绘制的内容正好适合最初的窗口大小。本节介绍如果绘制的内容不适合窗口的大小,需要做哪些工作。 下面扩展DrawShapes示例,以解释滚动的概念。为了使该示例更符合实际,首先创建一个BigShapes示例,该示例将矩形和椭圆画大一些。此时将使用Point、Size 和 Rectangle结构定义绘图区域,说明如何使用它们。进行了这样的修改后,Form1类的相关部分如下所示: // member fields private Point rectangleTopLeft = new Point(0, 0); private Size rectangleSize = new Size(200,200); private Point ellipseTopLeft = new Point(50, 200); private Size ellipseSize = new Size(200, 150); private Pen bluePen = new Pen(Color.Blue, 3); private Pen redPen = new Pen(Color.Red, 2); protected override void OnPaint( PaintEventArgs e ) { base.OnPaint(e); Graphics dc = e.Graphics; if (e.ClipRectangle.Top < 350 || e.ClipRectangle.Left < 250) { Rectangle rectangleArea = new Rectangle (rectangleTopLeft, rectangleSize); Rectangle ellipseArea = new Rectangle (ellipseTopLeft, ellipseSize); dc.DrawRectangle(bluePen, rectangleArea); dc.DrawEllipse(redPen, ellipseArea); } } 注意,这里还把Pen、Size和Point对象变成成员字段-- 这比每次需要绘图时都创建一个新Pen的效率高。 运行这个示例,得到如图33-6所示的结果。 这里有一个问题,图形在300×300像素的绘图区域中放不下。 一般情况下,如果文档太大,不能完全显示,应用程序就会添加滚动条,以便用户滚动窗口,查看其中选中的部分。这是另一个区域,在该区域中如果使用标准控件建立Windows窗体,就让.NET运行库和基类来处理。如果窗体上有各种控件,Form实例一般知道这些控件在哪里,如果其窗口比较小,Form实例就知道需要添加滚动条。Form实例还会自动添加滚动条,不仅如此,它还可以正确绘制用户滚动到的部分屏幕。此时,用户不需要在代码中做什么工作。但在本章中,我们要在屏幕上绘制图形,所以要帮助Form实例确定何时能滚动。 图 33-6 添加滚动条是很简单的。Form仍会处理所有的操作-- 因为它不知道绘图区域有多大。在上面的BigShapes示例中没有滚动条的原因是,Windows不知道它们需要滚动条。我们需要确定的是,矩形的大小从文档的左上角(或者是在进行任何滚动前的客户区域左上角)开始向下延伸,其大小应足以包含整个文档。本章把这个区域称为文档区域,在图33-7中可以看出,本例的文档区域应是(250, 350)像素。 使用相关的属性Form.AutoScrollMinSize即可确定文档的大小。因此给InitializeComponent()方法或Form1构造函数添加下述代码: private void InitializeComponent() { this.components = new System.ComponentModel.Container(); this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; this.Text = \this.BackColor = System.Drawing.Color.White; this.AutoScrollMinSize = new Size(250, 350); } 另外,AutoScrollMinSize属性还可以用Visual Studio 2008属性窗口设置。注意要访问Size类,需要添加下面的using语句:
共分享92篇相关文档