.net - ControlPaint.DrawReversibleFrame - 我应该如何删除绘制的矩形?

标签 .net vb.net winforms

考虑以下代码:

Dim recSelection As Rectangle?
Dim pntDown As Point?
Dim pntMove As Point?

Protected Overrides Sub OnMouseDown(e As Windows.Forms.MouseEventArgs)
    MyBase.OnMouseDown(e)

    pntDown = Me.PointToScreen(New Point(e.X, e.Y))
    pntMove = pntDown
End Sub

Protected Overrides Sub OnMouseUp(e As Windows.Forms.MouseEventArgs)
    If Me.recSelection.HasValue Then
        ControlPaint.DrawReversibleFrame(recSelection.Value, Me.BackColor, FrameStyle.Dashed)
    End If

    pntDown = Nothing
    pntMove = Nothing
    recSelection = Nothing

    MyBase.OnMouseUp(e)
End Sub

Protected Overrides Sub OnMouseMove(e As Windows.Forms.MouseEventArgs)
    MyBase.OnMouseMove(e)

    If pntDown.HasValue Then
        If recSelection.HasValue Then
            ControlPaint.DrawReversibleFrame(recSelection.Value, Me.BackColor, FrameStyle.Dashed)
        End If

        pntMove = Me.PointToScreen(New Point(Math.Max(Math.Min(e.X, Me.ClientSize.Width), 0), Math.Max(Math.Min(e.Y, Me.ClientSize.Height), 0)))

        recSelection = GetRectangle(pntDown, pntMove)

        ControlPaint.DrawReversibleFrame(Me.recSelection.Value, Me.BackColor, FrameStyle.Dashed)
    End If
End Sub

Private Function GetRectangle(pointA As Point, pointB As Point) As Rectangle
    Dim intLeft As Integer = Math.Min(pointA.X, pointB.X)
    Dim intTop As Integer = Math.Min(pointA.Y, pointB.Y)

    Dim intRight As Integer = Math.Max(pointA.X, pointB.X)
    Dim intBottom As Integer = Math.Max(pointA.Y, pointB.Y)

    Return Rectangle.FromLTRB(intLeft, intTop, intRight, intBottom)
End Function

基本上我想在控件及其子控件上绘制一个选择矩形。在 MSDN documentation ,它说要删除矩形,我应该记忆一下 DrawReversibleFrame 方法,该方法具有最初用于绘制它的相同参数。

不幸的是,在我看来这似乎不起作用。先前的选择矩形仍然绘制在控件上。在某一时刻,我最终可能会累积多个选择矩形:

enter image description here

(不是实际截图,我用MS Paint重现了效果)

我做错了什么?

更新:

我尝试了文档中显示的完全相同的代码,并且行为完全相同!可能与我的特定显示设置有关。我也在使用 Windows 8.1。这可能是问题所在吗?我明天会尝试在另一个系统上部署。

最佳答案

我最终使用了汉斯在上述评论中提出的“掩码”解决方案,并进行了一些改进:

Imports System.Drawing
Imports System.Drawing.Drawing2D
Imports System.Windows.Forms

Public NotInheritable Class RectangleDrawer

    Private Sub New()
    End Sub

    Public Shared Function Draw(parent As Form) As Rectangle

        ' Record the start point
        Dim startingPoint As Point = parent.PointToClient(Control.MousePosition)

        ' Create a transparent form on top of control and display it
        Using mask As New MaskForm(parent, startingPoint)
            mask.ShowDialog(parent)
        End Using

        Dim pos As Point = parent.PointToClient(Control.MousePosition)

        Dim x As Integer = Math.Min(startingPoint.X, pos.X)
        Dim y As Integer = Math.Min(startingPoint.Y, pos.Y)
        Dim w As Integer = Math.Abs(startingPoint.X - pos.X)
        Dim h As Integer = Math.Abs(startingPoint.Y - pos.Y)

        Return New Rectangle(x, y, w, h)
    End Function

    Private Class MaskForm
        Inherits Form

        Friend Sub New(parent As Form, startingPoint As Point)
            MyBase.New()

            Me._StartingPoint = startingPoint

            Me.FormBorderStyle = FormBorderStyle.None
            Me.BackColor = Color.Magenta
            Me.TransparencyKey = Me.BackColor
            Me.ShowInTaskbar = False
            Me.StartPosition = FormStartPosition.Manual

            Me.DoubleBuffered = True 'Prevents flickering (credits to Mike)

            Me.Size = parent.ClientSize
            Me.Location = parent.PointToScreen(Point.Empty)
        End Sub

        Dim _StartingPoint As Point

        Protected Overrides ReadOnly Property ShowWithoutActivation As Boolean
            Get
                ' Don't steal focus away
                Return True
            End Get
        End Property

        Protected Overrides Sub OnLoad(e As EventArgs)
            MyBase.Load(e)

            ' Grab the mouse
            Me.Capture = True
        End Sub

        Protected Overrides Sub OnMouseMove(e as MouseEventArgs)
            MyBase.OnMouseMove(e)

            ' Repaint the rectangle
            Me.Invalidate()
        End Sub

        Protected Overrides Sub OnMouseUp(e as MouseEventArgs)
            MyBase.OnMouseMove(e)

            ' Done, close mask
            Me.Close()
        End Sub

        Protected Overrides Sub OnPaint(e as PaintEventArgs)
            MyBase.OnPaint(e)

            ' Draw the current rectangle
            Dim pos As Point = Me.PointToClient(Control.MousePosition)

            Using pen As New Pen(Brushes.Black)
                pen.DashStyle = DashStyle.Dot

                e.Graphics.DrawLine(pen, _StartingPoint.X, _StartingPoint.Y, pos.X, mPos.Y)
                e.Graphics.DrawLine(pen, pos.X, _StartingPoint.Y, pos.X, pos.Y)
                e.Graphics.DrawLine(pen, pos.X, pos.Y, _StartingPoint.X, pos.Y)
                e.Graphics.DrawLine(pen, _StartingPoint.X, pos.Y, _StartingPoint.X, _StartingPoint.Y)
            End Using
        End Sub

    End Class

End Class

言语甚至无法描述我有多讨厌它,但这仍然是我见过的最好的解决方法。

关于.net - ControlPaint.DrawReversibleFrame - 我应该如何删除绘制的矩形?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29266145/

相关文章:

.net - Winforms 无法在 VS2012 中加载文件或程序集 'Microsoft.ReportDesigner, Version=10.0.0.0'

c# - WPF 的跨平台替代品

c# - 这个 C# .NET WinForms 应用程序我做错了什么?

c# - 如何将组框锚定到面板的 3 个边,但要尊重它的位置?

c# - 在实时图表中设置轴的最小值

c# - 在类中使用静态字段

c# - 是否可以在 Dynamics CRM (2013/2016) 中以编程方式禁用审计?

c# - 继承 : possible to change base reference to something else?

Vb.net 从字符串转换日期时间

c# - 具有 WinForm 和控制台界面的 .Net 程序