【问题标题】:How to draw child controls and custom drawings in expected order?如何按预期顺序绘制子控件和自定义绘图?
【发布时间】:2011-07-20 02:18:10
【问题描述】:

我可以控制自定义绘图,我们称之为Surface

我想在Surface 中嵌入一些winforms 控件。但我也想根据控件位置、大小等绘制一些自定义图纸(连接器)。

我试图将这些连接器绘制到子控件本身的责任,因此我的任何子控件的尺寸都更大,并包含所有必要的绘图。我在需要时使用Parent.InvokePaint 调用来绘制父背景(我也尝试了透明背景)。

缺点:当父背景在子OnPaint 事件中绘制时,它会擦除​​所有其他已绘制的相同控件。下图显示了结果。彩色区域是子控件的内容。

我还尝试将连接器绘制到Surface 并将子控件添加到Surface.Controls 列表中。

缺点:子控件总是在我的自定义绘图之上绘制(这发生在Surface.OnPaint),因为它们的绘制发生在队列的后面。

我的要求是:

我需要在我的Surface 中使用可操作的控件(接收任何鼠标和键盘事件、可聚焦等)。每个控件都会有一些自定义绘制的连接器来在表面上显示上下文。当控件重叠时,我希望所有内容都按预期顺序显示。

如何做到这一点?

【问题讨论】:

    标签: c# winforms drawing custom-controls


    【解决方案1】:

    我找到了解决问题的简单方法。

    我刚刚使用子控件(弹出)的 Region 属性来设置剪切路径:

    GraphicsPath path = new GraphicsPath();
    // add some shapes to path here, describing the control shape
    // ...
    this.Region = new Region(path);
    

    我之前不知道自定义路径裁剪。

    【讨论】:

      【解决方案2】:

      当您需要调整 WinForm 上控件的 z 顺序时,可以使用控件的 SendToFrontSendToBack 方法。更好的解决方案是转到控件的容器。在容器的 Controls 属性中有 SetChildIndex 方法,该方法可以独立设置其包含控件的 z 顺序。

      【讨论】:

      • 我已经使用了这个,例如当我选择控件时,我把它放在前面,但问题在于透明区域。
      • 这是否意味着在用文本框、标签、滚动条面板等填充我的容器时,我必须实现所有内置于 winforms 的功能??
      • 我不知道等,但是 - 标签是简单的 Graphics.DrawString,滚动条将作为子控件添加,因为它们位于边缘并且不是“透明”的,您可以创建广告- 用户必须输入内容时的 hoc 文本框,等等。
      • 好吧,我明白你的意思了。这真的是我应该做的。我们在这里处理第一个案例(图片#1)。我应该如何设置我的自定义控件,以便代替父背景代替红色椭圆,还有一部分控件在后面?这些是不同的控件,我不想将它们合并为一个。我想我现在很清楚了。
      • 如果我正确理解这里的情况,您最好将“控制在后面”作为您控制的一部分。
      【解决方案3】:

      @Dimitry - 感谢 C# 信息。这个问题确实帮助我开始将自定义图形放到自定义控件上。但是,我使用的是 Visual Basic .NET,所以这里有更多细节和 VB 视角。图形放置在表面上的 Zorder 也很关键。这是因为无法改变 .GrahicsPath 和 .FillRectangle 等 Drawing2D 对象的 z 顺序;只能更改控件的 Zorder。要隐藏现有控件的一部分并在其上绘制箭头,步骤如下。整个 Method 应该放在 Control 的 Paint Event 中;然后需要注意确保在重绘控件时触发绘制事件(这是另一个故事!):

      1. 创建一个附加到控件的 Graphics 对象
      2. 刷新控件
      3. 填充一个矩形以隐藏控件的部分现有信息。
      4. 创建并设置所需的形状作为剪贴蒙版(在下面的代码示例中,箭头)
      5. 用所需的颜色/图像或所需的任何内容填充形状。

      在下面的示例中,在基于 ListView 的自定义控件中应用,一个箭头被创建并放置在标题的左侧。它会遮盖不需要的 CheckBox,将所需的复选框留在视图中,如下所示:


      自您发布问题和上一个答案以来已经过去了几年。也许从那时起添加了现在在 .NET 帮助中的好信息。找到它是here,并提供更多详细信息和链接。


      Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)       'This is traps the default OnPaint for a Component, so it starts by calling the Base's Paint Event
          MyBase.OnPaint(e)
      
          'Add your custom paint code here - in this example, a Green Arrow
          AddArrowOverHeaderCheckBox()        
      End Sub
      Private Sub AddArrowOverHeaderCheckBox()
          'Adds an Arrow that is placed over the Checkbox of the 0th row, of a ListView, (over a Row that is used as a Header in this Custom Control).
      
          'Create a Rectangle into which to put the arrow
          Dim G As Graphics = Me.CreateGraphics               'Attach a Graphics Object to the Base
          Dim lvsi As ListViewItem.ListViewSubItem = Me.Items(0).SubItems(0)   'Get the first row; it is being used as a header in this case
          Dim CheckBoxWidth As Integer = Me.Bounds.X          'Calculate the size of the Control's CheckBox
          Dim CheckBoxHeight As Integer = lvsi.Bounds.Height
          Dim InflateBy As Integer = 1                        'Optional amount to resize the area in which the Arrow is to be placed
          Me.Refresh()                                        'Refresh the ListViewTab so that it does not overpaint the arrow that is about to be created at the End Sub
          Dim I As Integer = 0
          I = (CheckBoxHeight + 1) Mod 2
          Dim R As Rectangle = New Rectangle(lvsi.Bounds.X + Me.Margin.Left, lvsi.Bounds.Top, CheckBoxWidth, CheckBoxHeight + I) 'Make sure the height is an Odd number, to make a tidy arrow
          'myBrush.Color = Color.Red
          R.Inflate(InflateBy * 2, InflateBy)                  'Create a covering rectangle that is larger than the CheckBox on the Left of the CheckView Item in both dimensions
          Dim myBrush As New System.Drawing.SolidBrush(Me.BackColor)
          G.FillRectangle(myBrush, R)                         'Draw a filled Rectangle over the CheckBox in the Background colour for the ListViewTab to obscure the CheckBox
          Dim RW = R.Width
          Dim RH = R.Height
          I = CSng(RH) * 0.5 \ 2                              'Set a proportion of the arrow's width for its shaft, here 50%
          If RH Mod 2 <> 0 Then RH += 1                       'Ensure that the Height is an Odd number to make the Arrow axially symmetric
          '                                                   'Create a polygon in an Arrow shape that fits inside the Rectangle
          Dim polyArrow As Point() = {New Point(R.X + 0, I + R.Y), New Point(R.X + RW * 0.4, I + R.Y), New Point(R.X + RW * 0.4, 0 + R.Y), New Point(R.X + RW, RH * 0.5 + R.Y),
                                      New Point(R.X + RW * 0.4, RH + R.Y), New Point(R.X + RW * 0.4, RH - I + R.Y), New Point(R.X + 0, RH - I + R.Y)}
          Dim path As New Drawing2D.GraphicsPath()            'Create a Path shaped like an Arrow & sized proportionately to the size of the required Rectangle
          path.AddPolygon(polyArrow)                          'Turn the Path into a polygon
          Dim [reg] As New [Region](path)                     'Define a Graphics Region of the shape of the Arrow
          G.SetClip([reg], combineMode:=Drawing2D.CombineMode.Replace) 'Redefine the area; clipping will now prevent any drawing outside the area of the Arrow
          myBrush.Color = Color.Green
          G.FillRectangle(myBrush, R)                         'Draw a filled Green Rectangle, clipped to the Path shape
          'Dim pen As Pen = Pens.Black                         'Optionally: Draw a fine boundary in black
          'G.DrawPath(pen, path)                               'Optionally: Draw a fine boundary in black
          G.SetClip(Me.ClientRectangle)                       'Remove the Clip from the Graphics area - in case G is re-used
          myBrush.Dispose()                                   'Tidy up
          G.Dispose()
      End Sub
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-11-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-29
        • 2012-04-03
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多