“显示对话框"方法无法正常工作(设置 Form 父级时?) [英] "ShowDialog" method is not working properly (when setting the Form parent?)

查看:49
本文介绍了“显示对话框"方法无法正常工作(设置 Form 父级时?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm trying to write a Form that should draw a rectangle over the screen to select an screen region, the question and the solution(s) can be seen in other StackOverflow post, here. I've adapted the marked solution of @ZeroWorks to my needs, but the problem now is that I can't find the way to use the Form like I require.

这就是我想使用它的方式:

This is how I would like to use it:

    Dim RegionRect As Rectangle = Rectangle.Empty

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

我只想使用 ShowDialog 方法来显示表单并停止执行,直到用户选择该区域,因为我关闭了 OnMouseUp 事件表单,但是如果我尝试使用 ShowDialog 方法,我将无法绘制/查看矩形,顺便说一下,如果我使用 Show 方法,它可以正常工作但就像我说的,我需要使用 ShowDialog 方法来等待表单的响应"以继续执行下一个指令,我不明白为什么会发生这个问题,我是什么我失踪了?,我该如何解决这个问题?.

I just would like to use the ShowDialog method to show the Form and stop the execution until the region is selected by the user 'cause on the OnMouseUp event I close the form, but If I try to use the ShowDialog method I'm not able to draw/see the rectangle, by the way if I use the Show method it works properly but like I've said I need to use instead the ShowDialog method to wait a "response" from the Form to proceed with the next instructions, I don't understand why happens this problem, what I'm missing?, how I could fix this?.

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

This is the (full) code of the custom region selector:

''' <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

推荐答案

我不会用 formdialog 方法来做,你会遇到很多麻烦让它工作,表单对话框会阻塞执行并等待它关闭.但是有一个解决方案......我会使用回调.所以,首先定义一个委托:

I wouldn't do it with formdialog method, you will have a lot of troubles to get it work, form dialog blocks execution and waits until its closed. But there's is a solution instead... I would use a Callback. So, first define a Delegate:

Public Delegate Sub RegionSelectedDelegate(Region As Rectangle)

然后在调用表单中,在子或函数中,因为使用会破坏表单改变它:

Then in the calling form, in a sub or function, since using will destroy form change it:

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 类中定义一个新的属性回调,并在 onmouseup 事件处理程序中调用此委托:

That delegate will be called from drawing form on onmouseup (when the rectangle is drawn) and will be received by RegionSelector Class. So, will define a new property Callback in RegionSelector Class, and invoke this delegate in onmouseup event handler:

''' <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

就是这样,没有显示任何阻塞的模态形式,流程保持其逻辑并且可以正常工作.希望有帮助.

And that's all, no blocking modal forms are shown, the flow stills its logic and it works. Hope it helps.

这篇关于“显示对话框"方法无法正常工作(设置 Form 父级时?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆