“ShowDialog”方法无法正常工作(设置Form父级?)

时间:2014-06-03 05:52:34

标签: .net vb.net winforms parent

我正在尝试编写一个应该在屏幕上绘制矩形以选择屏幕区域的表单,问题和解决方案可以在其他StackOverflow帖子here中看到。 我已经根据我的需要调整了@ ZeroWorks 的标记解决方案,但现在的问题是我找不到像我要求的那样使用表单的方式。

这就是我想用它的方式:

    Dim RegionRect As Rectangle = Rectangle.Empty

    Using Selector As New RegionSelector
        Selector.ShowDialog()
        RegionRect = Selector.SelectedRegion
    End Using

我只是想使用ShowDialog方法来显示表单并停止执行,直到用户在OnMouseUp事件中选择该区域我关闭表单,但是如果我尝试使用我无法绘制/看到矩形的ShowDialog方法,顺便说一句,如果我使用Show方法它可以正常工作但是就像我说过我需要使用而不是ShowDialog方法等待表单中的“响应”继续执行下一条指令,我不明白为什么会出现这个问题,我错过了什么?,我怎么能解决这个问题?。

这是自定义区域选择器的(完整)代码:

''' <summary>
''' Selects a region on the Screen.
''' </summary>
Public Class RegionSelector : Inherits Form

#Region " Properties "

    ''' <summary>
    ''' Gets or sets the border size of the region selector.
    ''' </summary>
    ''' <value>The size of the border.</value>
    Public Property BorderSize As Integer = 2

    ''' <summary>
    ''' Gets or sets the border color of the region selector.
    ''' </summary>
    ''' <value>The color of the border.</value>
    Public Property BorderColor As Color = Color.Red

    ''' <summary>
    ''' Gets the rectangle that contains the selected region.
    ''' </summary>
    Public ReadOnly Property SelectedRegion As Rectangle
        Get
            Return Me.DrawRect
        End Get
    End Property

#End Region

#Region " Objects "

    ''' <summary>
    ''' Indicates the initial location when the mouse left button is clicked.
    ''' </summary>
    Private InitialLocation As Point = Point.Empty

    ''' <summary>
    ''' The rectangle where to draw the region.
    ''' </summary>
    Public DrawRect As Rectangle = Rectangle.Empty

    ''' <summary>
    ''' The Graphics object to draw on the screen.
    ''' </summary>
    Private ScreenGraphic As Graphics = Graphics.FromHwnd(IntPtr.Zero)

    Public IsDrawing As Boolean = False

    Dim DrawSize As Size

    Dim DrawForm As Form

#End Region

#Region " Constructors "

    ''' <summary>
    ''' Initializes a new instance of the <see cref="RegionSelector"/> class.
    ''' </summary>
    Public Sub New()
    End Sub

    ''' <summary>
    ''' Initializes a new instance of the <see cref="RegionSelector" /> class.
    ''' </summary>
    ''' <param name="BorderSize">Indicates the border size of the region selector.</param>
    ''' <param name="BorderColor">Indicates the border color of the region selector.</param>
    Public Sub New(ByVal BorderSize As Integer,
                   ByVal BorderColor As Color)

        Me.BorderSize = BorderSize
        Me.BorderColor = BorderColor

    End Sub

#End Region

#Region " Event Handlers "

    ''' <summary>
    ''' Handles the Load event of the RegionSelector.
    ''' </summary>
    ''' <param name="sender">The source of the event.</param>
    ''' <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
    Private Sub RegionSelector_Load(sender As Object, e As EventArgs) Handles Me.Load

        Me.SuspendLayout()

        Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None
        Me.BackColor = System.Drawing.Color.Black
        Me.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None
        Me.CausesValidation = False
        Me.ClientSize = New System.Drawing.Size(0, 0)
        Me.ControlBox = False
        Me.Cursor = System.Windows.Forms.Cursors.Cross
        Me.DoubleBuffered = True
        Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
        Me.MaximizeBox = False
        Me.MinimizeBox = False
        Me.Name = "RegionSelector"
        Me.Opacity = 0.15R
        Me.ShowIcon = False
        Me.ShowInTaskbar = False
        Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
        Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
        Me.TopMost = False
        Me.WindowState = System.Windows.Forms.FormWindowState.Maximized

        Me.ResumeLayout(True)

        Me.DrawForm = New DrawingRegionClass(Me)
        With DrawForm
            .BackColor = Color.Tomato
            .TopLevel = True
            .TransparencyKey = Color.Tomato
            .TopMost = False
            .FormBorderStyle = Windows.Forms.FormBorderStyle.None
            .ControlBox = False
            .WindowState = FormWindowState.Maximized
        End With

        Me.AddOwnedForm(Me.DrawForm)
        Me.DrawForm.Show()

    End Sub

    ''' <summary>
    ''' Raises the <see cref="E:System.Windows.Forms.Control.MouseDown" /> event.
    ''' </summary>
    ''' <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.</param>
    Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)

        If e.Button = MouseButtons.Left Then

            Me.InitialLocation = e.Location
            Me.IsDrawing = True

        End If

    End Sub

    ''' <summary>
    ''' Raises the <see cref="E:System.Windows.Forms.Control.MouseUp" /> event.
    ''' </summary>
    ''' <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.</param>
    Protected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)

        Me.IsDrawing = False
        Me.Close()

    End Sub

    ''' <summary>
    ''' Raises the <see cref="E:System.Windows.Forms.Control.MouseMove" /> event.
    ''' </summary>
    ''' <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.</param>
    Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)

        If Me.IsDrawing Then

            Me.DrawSize = New Size(e.X - Me.InitialLocation.X, e.Y - Me.InitialLocation.Y)
            Me.DrawRect = New Rectangle(Me.InitialLocation, Me.DrawSize)

            If Me.DrawRect.Height < 0 Then
                Me.DrawRect.Height = Math.Abs(Me.DrawRect.Height)
                Me.DrawRect.Y -= Me.DrawRect.Height
            End If

            If Me.DrawRect.Width < 0 Then
                Me.DrawRect.Width = Math.Abs(Me.DrawRect.Width)
                Me.DrawRect.X -= Me.DrawRect.Width
            End If

            Me.DrawForm.Invalidate()

        End If

    End Sub

#End Region

End Class

Public Class DrawingRegionClass : Inherits Form

    Private DrawParent As RegionSelector

    Public Sub New(ByVal Parent As Form)

        Me.DrawParent = Parent

    End Sub

    Protected Overrides Sub OnPaintBackground(ByVal e As PaintEventArgs)

        Dim Bg As Bitmap
        Dim Canvas As Graphics

        If Me.DrawParent.IsDrawing Then

            Bg = New Bitmap(Width, Height)
            Canvas = Graphics.FromImage(Bg)
            Canvas.Clear(Color.Tomato)
            Canvas.DrawRectangle(Pens.Red, Me.DrawParent.DrawRect)
            Canvas.Dispose()
            e.Graphics.DrawImage(Bg, 0, 0, Width, Height)
            Bg.Dispose()

        Else
            MyBase.OnPaintBackground(e)
        End If

    End Sub

End Class

1 个答案:

答案 0 :(得分:1)

我不会用formdialog方法做这件事,你会遇到很多麻烦让它工作,形成对话框块执行并等待它关闭。但是有一个解决方案......我会使用回调。因此,首先定义一个委托:

Public Delegate Sub RegionSelectedDelegate(Region As Rectangle)

然后在调用形式中,在子或函数中,因为使用将破坏形式更改它:

Dim RegionRect As Rectangle = Rectangle.Empty
Dim Working As Boolean = False

Public Sub GetRectangle()
    Dim Callback As RegionSelectedDelegate
    Dim Selector As New RegionSelector

    If Working Then Exit Sub 'Only one selection at once!
    Working = True
    Callback = New RegionSelectedDelegate(AddressOf RectangleDrawn)

    With Selector
        .Callback = Callback
        .Show()
    End With
    ' Don't do any stuff here... do it in Rectangle Drawn...
End Sub

...

Public Sub RectangleDrawn(Region as Rectangle)   
    Working = false 'Allow draw again.
    Me.RegionRect=Region
    MessageBox.Show("Do next steps!")
    ' Some stuff Here
End Sub

该委托将从onmouseup上的绘图表单调用(绘制矩形时),并由RegionSelector类接收。因此,将在RegionSelector类中定义一个新属性Callback,并在onmouseup事件处理程序中调用此委托:

''' <summary>
''' Selects a region on the Screen.
''' </summary>
Public Class RegionSelector : Inherits Form

#Region " Properties "

''' <summary>
''' Callback to be invoked when drawing is done...
''' </summary>
''' <value>Delegate of Region Selected</value>
Public Property Callback As RegionSelectedDelegate = Nothing


''' <summary>
''' Gets or sets the border size of the region selector.
''' </summary>
''' <value>The size of the border.</value>
Public Property BorderSize As Integer = 2

''' <summary>
''' Gets or sets the border color of the region selector.
''' </summary>
''' <value>The color of the border.</value>
Public Property BorderColor As Color = Color.Red

''' <summary>
''' Gets the rectangle that contains the selected region.
''' </summary>
Public ReadOnly Property SelectedRegion As Rectangle
    Get
        Return Me.DrawRect
    End Get
End Property

#End Region

#Region " Objects "

''' <summary>
''' Indicates the initial location when the mouse left button is clicked.
''' </summary>
Private InitialLocation As Point = Point.Empty

''' <summary>
''' The rectangle where to draw the region.
''' </summary>
Public DrawRect As Rectangle = Rectangle.Empty

''' <summary>
''' The Graphics object to draw on the screen.
''' </summary>
Private ScreenGraphic As Graphics = Graphics.FromHwnd(IntPtr.Zero)

Public IsDrawing As Boolean = False

Dim DrawSize As Size

Dim DrawForm As Form

#End Region

#Region " Constructors "

''' <summary>
''' Initializes a new instance of the <see cref="RegionSelector"/> class.
''' </summary>
Public Sub New()
End Sub

''' <summary>
''' Initializes a new instance of the <see cref="RegionSelector" /> class.
''' </summary>
''' <param name="BorderSize">Indicates the border size of the region selector.</param>
''' <param name="BorderColor">Indicates the border color of the region selector.</param>
Public Sub New(ByVal BorderSize As Integer,
               ByVal BorderColor As Color)

    Me.BorderSize = BorderSize
    Me.BorderColor = BorderColor

End Sub

#End Region

#Region " Event Handlers "

''' <summary>
''' Handles the Load event of the RegionSelector.
''' </summary>
''' <param name="sender">The source of the event.</param>
''' <param name="e">The <see cref="EventArgs"/> instance containing the event data.</param>
Private Sub RegionSelector_Load(sender As Object, e As EventArgs) Handles Me.Load

    Me.SuspendLayout()

    Me.AutoScaleMode = System.Windows.Forms.AutoScaleMode.None
    Me.BackColor = System.Drawing.Color.Black
    Me.BackgroundImageLayout = System.Windows.Forms.ImageLayout.None
    Me.CausesValidation = False
    Me.ClientSize = New System.Drawing.Size(0, 0)
    Me.ControlBox = False
    Me.Cursor = System.Windows.Forms.Cursors.Cross
    Me.DoubleBuffered = True
    Me.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None
    Me.MaximizeBox = False
    Me.MinimizeBox = False
    Me.Name = "RegionSelector"
    Me.Opacity = 0.15R
    Me.ShowIcon = False
    Me.ShowInTaskbar = False
    Me.SizeGripStyle = System.Windows.Forms.SizeGripStyle.Hide
    Me.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen
    Me.TopMost = False
    Me.WindowState = System.Windows.Forms.FormWindowState.Maximized

    Me.ResumeLayout(True)

    Me.DrawForm = New DrawingRegionClass(Me)
    With DrawForm
        .BackColor = Color.Tomato
        .TopLevel = True
        .TransparencyKey = Color.Tomato
        .TopMost = False
        .FormBorderStyle = Windows.Forms.FormBorderStyle.None
        .ControlBox = False
        .WindowState = FormWindowState.Maximized
    End With

    Me.AddOwnedForm(Me.DrawForm)
    Me.DrawForm.Show()

End Sub

''' <summary>
''' Raises the <see cref="E:System.Windows.Forms.Control.MouseDown" /> event.
''' </summary>
''' <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.</param>
Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)

    If e.Button = MouseButtons.Left Then

        Me.InitialLocation = e.Location
        Me.IsDrawing = True

    End If

End Sub

''' <summary>
''' Raises the <see cref="E:System.Windows.Forms.Control.MouseUp" /> event.
''' </summary>
''' <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.</param>
Protected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
    'Do the callback here!
    Me.IsDrawing = False
    Callback.Invoke(SelectedRegion)
    Me.Close() 'Must be called last.
End Sub

''' <summary>
''' Raises the <see cref="E:System.Windows.Forms.Control.MouseMove" /> event.
''' </summary>
''' <param name="e">A <see cref="T:System.Windows.Forms.MouseEventArgs" /> that contains the event data.</param>
Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)

    If Me.IsDrawing Then

        Me.DrawSize = New Size(e.X - Me.InitialLocation.X, e.Y - Me.InitialLocation.Y)
        Me.DrawRect = New Rectangle(Me.InitialLocation, Me.DrawSize)

        If Me.DrawRect.Height < 0 Then
            Me.DrawRect.Height = Math.Abs(Me.DrawRect.Height)
            Me.DrawRect.Y -= Me.DrawRect.Height
        End If

        If Me.DrawRect.Width < 0 Then
            Me.DrawRect.Width = Math.Abs(Me.DrawRect.Width)
            Me.DrawRect.X -= Me.DrawRect.Width
        End If

        Me.DrawForm.Invalidate()

    End If

End Sub

#End Region

End Class

Public Class DrawingRegionClass : Inherits Form

Private DrawParent As RegionSelector

Public Sub New(ByVal Parent As Form)

    Me.DrawParent = Parent

End Sub

Protected Overrides Sub OnPaintBackground(ByVal e As PaintEventArgs)

    Dim Bg As Bitmap
    Dim Canvas As Graphics

    If Me.DrawParent.IsDrawing Then

        Bg = New Bitmap(Width, Height)
        Canvas = Graphics.FromImage(Bg)
        Canvas.Clear(Color.Tomato)
        Canvas.DrawRectangle(Pens.Red, Me.DrawParent.DrawRect)
        Canvas.Dispose()
        e.Graphics.DrawImage(Bg, 0, 0, Width, Height)
        Bg.Dispose()

    Else
        MyBase.OnPaintBackground(e)
    End If

End Sub

End Class

就是这样,没有显示阻塞模态形式,流程仍然是它的逻辑并且它起作用。希望它有所帮助。