65.9K
CodeProject 正在变化。 阅读更多。
Home

在 WinForms 控件上绘制

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.86/5 (27投票s)

2008年5月14日

CPOL

4分钟阅读

viewsIcon

208040

downloadIcon

12257

使用 Graphics 对象在窗体控件的顶部绘制几乎任何东西

Form1

GraphicalOverlayDemo1.PNG GraphicalOverlayDemo2.PNG

Form2

GraphicalOverlayDemo3.PNG GraphicalOverlayDemo4.PNG GraphicalOverlayDemo5.PNG

引言

GraphicalOverlay 组件在窗体控件的顶部进行绘制。它本质上就像在窗体上铺了一层玻璃,然后在玻璃上进行绘制。我使用这个组件在控件之间绘制线条,以帮助用户理解 UI 中复杂的关联。我很少使用它,但有时你只需要一个大红箭头来表示:这会影响那个!如果做得好,效果会相当优雅。

Using the Code

要使用 GraphicalOverlay 组件,请按照以下步骤操作:

  1. 将以下两个文件复制到项目的目录中:GraphicalOverlay.csGraphicalOverlay.designer.cs
  2. GraphicalOverlay.cs 添加到你的项目中。Visual Studio 会自动包含 GraphicalOverlay.designer.cs

    编译项目。这将在 Visual Studio 工具箱中创建一个 GraphicalOverlay 组件。

  3. GraphicalOverlay 组件从工具箱拖放到窗体设计器表面。该组件将自动命名为 graphicalOverlay1
  4. 在你的窗体中,为 graphicalOverlay1 创建一个 paint 事件处理程序(graphicalOverlay1_Paint())。
  5. 在你的窗体构造函数中,在 InitializeComponents(); 行之后,添加以下行:
    public Form1()
    {
        InitializeComponent();
    
        graphicalOverlay1.Owner = this;
    }
  6. graphicalOverlay1_Paint()(参见步骤 5)中,使用 e.Graphics 以窗体相对坐标绘制任何你想要的东西。
    private void graphicalOverlay1_Paint(object sender, PaintEventArgs e)
    {
        // This event will fire for the form and each control on the form.
        // The graphical overlay component will have already transformed the
        // graphics object to use the form's coordinate system, 
        // so no control-specific calculations are required.
    
        Rectangle rect = this.ClientRectangle;
        rect.Inflate(-10, -10);
    
        using(Pen pen = new Pen(Color.Red, 5))
            e.Graphics.DrawEllipse(pen, rect);
    
        using(Font font = new Font("Arial", 14))
            e.Graphics.DrawString("Now is the time.", 
                                  font, Brushes.Green, 60, 110);
    
        [...]
    }
  7. 要绘制控件相对图形,请使用 Coordinates() 方法获取控件的窗体相对坐标。请参阅演示代码中的 Form1.graphicalOverlay1_Paint() 事件处理程序以获取示例。
    private void graphicalOverlay1_Paint(object sender, PaintEventArgs e)
    {
        [...]
        // To draw relative to a control, use the Coordinates method.
        using (Pen pen = new Pen(Color.Blue, 3))
            e.Graphics.DrawEllipse(pen, pictureBox1.Coordinates());
    }

关注点

该组件包含以下事件处理程序:

  • Form_Resize
  • Control_Paint

当设置了 graphicalOverlay1.Owner 属性后,该组件会将它的 Form_Resize 事件处理程序连接到所有者窗体的 Resize 事件。然后,该组件将其 Control_Paint 事件处理程序附加到所有者窗体(包括所有者窗体本身)的每个控件的 Paint 事件上。

当每个控件被重绘时,组件会处理 Paint 事件,转换 e.Graphics 对象的坐标,然后触发它自己的 Paint 事件,该事件将被窗体的 graphicalOverlay1_Paint 事件处理程序处理。

由于传递给 graphicalOverlay1_Paint()e.Graphics 对象已被转换为使用窗体的坐标系,因此所有绘图逻辑都是窗体相对的。就像在窗体的客户区内绘图一样即可。

然而,这种方法使得相对于控件进行绘图变得困难。因此,为了使控件相对绘图更容易,我在 System.Windows.Forms.Control 类中添加了一个名为 Coordinates() 的扩展方法。Coordinates() 方法将控件的位置转换为窗体相对坐标。只需使用 Coordinates(control) 而不是 control.Location 进行绘图即可。

由于图形叠加层可以绘制在窗体的所有控件之上,因此重绘它需要使整个窗体失效。调用组件的 Invalidate() 方法将使窗体及其每个控件失效。

限制

该组件响应每个控件的 Paint 事件。TextBox 控件不触发 Paint 事件,因此该组件无法在 TextBox 控件上进行绘制。可以使用第三方文本框控件,但我没有测试过任何一个。

该组件只能在控件的客户区域上进行绘制。某些控件包含不属于其客户区域的边框,因此该组件无法绘制在边框上。解决此问题的一个方法是关闭控件的边框,然后使用该组件进行绘制。

该组件只能在窗体的客户区域内进行绘制。它无法绘制在窗体的标题栏或边框上,也无法绘制在窗体之间。要模拟在窗体边框上绘制,你需要关闭窗体的边框并使用该组件进行绘制,并重新实现所有丢失的功能。

演示

我包含了两个演示窗体,以帮助你了解如何实现自己的 graphicalOverlay1_Paint 事件处理程序。

Form1.cs 是带有带有红色和蓝色圆环以及绿色文本的图片的那个。

注意:当 Form1 演示运行时,请几次调整窗体大小。

Form2.cs 是带有分组框和单选按钮的演示。

注意:要切换 Form1Form2 演示,你必须修改 Program.cs 文件以运行 Form1Form2。默认情况下,演示将运行 Form2

Form2 演示中,graphicalOverlay1_Paint() 中的代码包含大量硬编码值。我可以计算这些值,但这只会使代码更难阅读。如果你的 UI 文化与我不同,或者你的字体配置与我不同,这些硬编码值可能无法完全正常工作。文章开头的截图将显示它们应该是什么样子。

© . All rights reserved.