我有工作代码但是当将表单移动到屏幕边界时,我有时会形成闪烁的形状。它看起来并不好。
对此有更好的解决方案吗?
Private Sub Form1_Move(sender As Object, e As EventArgs) Handles Me.Move
Dim p As Point
p = Me.Location
Dim screenWidth As Integer = Screen.PrimaryScreen.Bounds.Width
Dim screenHeight As Integer = Screen.PrimaryScreen.Bounds.Height
Dim TaskBarH As Integer = screenHeight - Screen.PrimaryScreen.WorkingArea.Height
If p.X < 0 Then
Me.Location = New System.Drawing.Point(0, p.Y)
ElseIf p.X > screenWidth - Me.Size.Width Then
Me.Location = New System.Drawing.Point(screenWidth - Me.Size.Width, p.Y)
End If
If p.Y < 0 Then
Me.Location = New System.Drawing.Point(p.X, 0)
ElseIf p.Y > screenHeight - Me.Size.Height - TaskBarH Then
Me.Location = New System.Drawing.Point(p.X, screenHeight - Me.Size.Height - TaskBarH)
End If
End Sub
答案 0 :(得分:1)
当您移动表单时,表单闪烁的原因是因为每次在不同位置重新绘制表单时,都会触发Move
事件。要了解多少,试试这个:
Option Strict On
Option Explicit On
Public Class Form1
Dim counter As Int64
Private Sub Form1_Move(sender As Object, e As EventArgs) Handles Me.Move
counter += 1
Console.WriteLine(counter)
End Sub
End Class
你会注意到,即使只是一个像素移动表单,事件也会被触发。您将表单向左移动100像素,该事件将触发100次。要在每次重绘表单时检查位置,然后计算每个单独的点是否在您想要的范围内,需要做很多工作。点和矩形的所有持续计算等都会导致巨大的开销,结果是没有足够的资源时间来重绘表单中的所有控件,因此表单会闪烁。
更好的选择是在表单完成移动时只执行一次所有数学运算,如果表单在屏幕边界之外,则更正表单。只要用户完成重新调整大小或移动表单,就会触发Form.ResizeEnd
事件。通过利用此事件,代码将仅在用户完成操作后被调用一次,并且表单已在屏幕上重新绘制。然后,如果表单超出了您想要的范围,您可以将表单移动到一个位置。
我不是硬编码使用Screen.PrimaryScreen
,而是动态获取表单所在的屏幕。这允许用户将表单移动到多监视器环境中的不同屏幕。
Option Strict On
Option Explicit On
Public Class Form1
Private Sub Form1_resizeEnd(sender As Object, e As EventArgs) Handles Me.ResizeEnd
Dim screenArea As Rectangle = Screen.GetWorkingArea(Me.Location)
Dim formArea As Rectangle = Me.DesktopBounds
If Me.WindowState = FormWindowState.Normal AndAlso Not screenArea.Contains(formArea) Then
If formArea.Top < screenArea.Top Then Me.Top = 0
If formArea.Left < screenArea.Left Then Me.Left = 0
If formArea.Right > screenArea.Right Then Me.Left = Me.Left - (formArea.Right - screenArea.Right)
If formArea.Bottom > screenArea.Bottom Then Me.Top = Me.Top - (formArea.Bottom - screenArea.Bottom)
End If
End Sub
End Class
答案 1 :(得分:1)
您可以尝试限制鼠标拖动表单的位置。
Option Strict On
Option Explicit On
Option Infer Off
Imports System.Runtime.InteropServices
Public Class Form1
Public Declare Function SetCursorPos Lib "user32.dll" (X As Integer, Y As Integer) As Boolean
Public Function AbsoluteFormMousePosition() As Point
Dim mousePos As Point = PointToClient(MousePosition)
Dim hBorderWidth As Integer = (Me.Width - Me.ClientRectangle.Width) \ 2
Dim vBorderWidth As Integer = hBorderWidth
Dim TitleHeight As Integer = (Me.Height - Me.ClientRectangle.Height) - vBorderWidth
Dim newPos As New Point(mousePos.X + hBorderWidth, mousePos.Y + TitleHeight)
Return newPos
End Function
Function TryOffest(range As Range, find As Integer, ByRef newValue As Integer) As Boolean
If Not range.Contains(find) Then
Dim diff As Integer
diff = If(find > range.Upper, find - range.Upper, range.Lower - find)
newValue += If(find > range.Upper, -(diff), diff)
Return True
End If
Return False
End Function
Private Sub Form1_Move(sender As Object, e As EventArgs) Handles Me.Move
Dim mousePos As Point = MousePosition
Dim newX As Integer = mousePos.X
Dim newY As Integer = mousePos.Y
Dim vChanged, hChanged As Boolean
Dim hBorder As Integer = Me.Width - Me.ClientRectangle.Width
Dim vBorder As Integer = Me.Height - Me.ClientRectangle.Height
Dim adjX As Integer = Me.PointToClient(mousePos).X
Dim adjY As Integer = Me.PointToClient(mousePos).Y
Dim titleMousePosition As Integer = hBorder - Me.PointToClient(mousePos).Y
Dim verticalBounds As New Range(AbsoluteFormMousePosition.Y + 2, Screen.PrimaryScreen.WorkingArea.Height - (Me.Height - vBorder - adjY + 2))
Dim horizontalBounds As New Range(adjX + 2, Screen.PrimaryScreen.WorkingArea.Width - (Me.Width - hBorder - adjX + 2))
vChanged = TryOffest(verticalBounds, mousePos.Y, newY)
hChanged = TryOffest(horizontalBounds, mousePos.X, newX)
If vChanged OrElse hChanged Then SetCursorPos(newX, newY)
End Sub
End Class
Public Class Range
Public Lower, Upper As Integer
Sub New(lower As Integer, upper As Integer)
Me.Lower = lower : Me.Upper = upper
End Sub
Public Function Contains(number As Integer) As Boolean
If number >= Lower AndAlso number <= Upper Then Return True Else Return False
End Function
End Class