我正在尝试编写一个应该在屏幕上绘制矩形以选择屏幕区域的表单,问题和解决方案可以在其他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
答案 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
就是这样,没有显示阻塞模态形式,流程仍然是它的逻辑并且它起作用。希望它有所帮助。