将表单限制在屏幕的工作区域而不会闪烁

时间:2015-05-05 13:47:05

标签: vb.net forms drawing screen

我有工作代码但是当将表单移动到屏幕边界时,我有时会形成闪烁的形状。它看起来并不好。

对此有更好的解决方案吗?

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

2 个答案:

答案 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