一个 .NET 窗口吸附屏幕的功能






4.81/5 (25投票s)
一篇关于将 Windows 窗体吸附到桌面屏幕边缘的文章。
引言
本文演示了如何在您的应用程序中添加吸附屏幕功能。此功能允许您将窗口拖动到屏幕边缘附近,并使窗口自动被拉向该边缘,就像磁铁一样。这里已经有一个不错的非托管 C++ 实现 在这里。
背景
在 TrayGames,我们有一个客户端,为您的计算机提供聊天和游戏。我们的客户端完全用 .NET 2.0 编写,使用 C# 和 VB.NET 的组合。我们希望我们的客户端具有像 Winamp 和 Skype 等其他流行应用程序所具有的吸附屏幕功能。
Using the Code
要为您的应用程序添加吸附屏幕功能,您必须重写 Windows.Forms.Form.WndProc
方法并处理 WM_WINDOWPOSCHANGING
消息。您的处理程序将调用我的自定义 SnapToDesktopBorder
方法
Imports system.Runtime.InteropServices
Public Class Form1
Private Const mSnapOffset As Integer = 35
Private Const WM_WINDOWPOSCHANGING As Integer = &H46
<StructLayout(LayoutKind.Sequential)> _
Public Structure WINDOWPOS
Public hwnd As IntPtr
Public hwndInsertAfter As IntPtr
Public x As Integer
Public y As Integer
Public cx As Integer
Public cy As Integer
Public flags As Integer
End Structure
Protected Overrides Sub WndProc(ByRef m As Message)
' Listen for operating system messages
Select Case m.Msg
Case WM_WINDOWPOSCHANGING
SnapToDesktopBorder(Me, m.LParam, 0)
End Select
MyBase.WndProc(m)
End Sub
该功能的核心在于 SnapToDesktopBorder
方法的实现。它计算到桌面屏幕边缘的距离,并根据需要重新定位窗口
Public Shared Sub SnapToDesktopBorder(ByVal clientForm _
As Form, ByVal LParam As IntPtr, ByVal widthAdjustment As Integer)
If clientForm Is Nothing Then
' Satisfies rule: Validate parameters
Throw New ArgumentNullException("clientForm")
End If
' Snap client to the top, left, bottom or right desktop border
' as the form is moved near that border.
Try
' Marshal the LPARAM value which is a WINDOWPOS struct
Dim NewPosition As New WINDOWPOS
NewPosition = CType(Runtime.InteropServices.Marshal.PtrToStructure( _
LParam, GetType(WINDOWPOS)), WINDOWPOS)
If NewPosition.y = 0 OrElse NewPosition.x = 0 Then
Return ' Nothing to do!
End If
' Adjust the client size for borders and caption bar
Dim ClientRect As Rectangle = _
clientForm.RectangleToScreen(clientForm.ClientRectangle)
ClientRect.Width += _
SystemInformation.FrameBorderSize.Width - widthAdjustment
ClientRect.Height += (SystemInformation.FrameBorderSize.Height + _
SystemInformation.CaptionHeight)
' Now get the screen working area (without taskbar)
Dim WorkingRect As Rectangle = _
Screen.GetWorkingArea(clientForm.ClientRectangle)
' Left border
If NewPosition.x >= WorkingRect.X - mSnapOffset AndAlso _
NewPosition.x <= WorkingRect.X + mSnapOffset Then
NewPosition.x = WorkingRect.X
End If
' Get screen bounds and taskbar height
' (when taskbar is horizontal)
Dim ScreenRect As Rectangle = _
Screen.GetBounds(Screen.PrimaryScreen.Bounds)
Dim TaskbarHeight As Integer = _
ScreenRect.Height - WorkingRect.Height
' Top border (check if taskbar is on top
' or bottom via WorkingRect.Y)
If NewPosition.y >= -mSnapOffset AndAlso _
(WorkingRect.Y > 0 AndAlso NewPosition.y <= _
(TaskbarHeight + mSnapOffset)) OrElse _
(WorkingRect.Y <= 0 AndAlso NewPosition.y <= _
(mSnapOffset)) Then
If TaskbarHeight > 0 Then
NewPosition.y = WorkingRect.Y ' Horizontal Taskbar
Else
NewPosition.y = 0 ' Vertical Taskbar
End If
End If
' Right border
If NewPosition.x + ClientRect.Width <= _
WorkingRect.Right + mSnapOffset AndAlso _
NewPosition.x + ClientRect.Width >= _
WorkingRect.Right - mSnapOffset Then
NewPosition.x = WorkingRect.Right - (ClientRect.Width + _
SystemInformation.FrameBorderSize.Width)
End If
' Bottom border
If NewPosition.y + ClientRect.Height <= _
WorkingRect.Bottom + mSnapOffset AndAlso _
NewPosition.y + ClientRect.Height >= _
WorkingRect.Bottom - mSnapOffset Then
NewPosition.y = WorkingRect.Bottom - (ClientRect.Height + _
SystemInformation.FrameBorderSize.Height)
End If
' Marshal it back
Runtime.InteropServices.Marshal.StructureToPtr(NewPosition, _
LParam, True)
Catch ex As ArgumentException
End Try
End Sub
End Class
您可以调整 mSnapOffset
成员变量来调整窗口与屏幕边缘之间的距离,从而发生吸附。请注意,widthAdjustment
参数可用作调整因子,以防您的客户端具有特殊的宽度要求。 这就是全部!
关注点
如果您想学习一些定位 Windows Forms 的创造性方法,那么这篇文章很有趣。 虽然这并不是一个最复杂的主题,但我希望我能为某人节省一点时间来解决这个问题! 如果您有兴趣创建自己的多人在线游戏,您应该查看可从 TrayGames 网站下载的 TGSDK。