65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.81/5 (25投票s)

2006年8月24日

CPOL

1分钟阅读

viewsIcon

103705

downloadIcon

2460

一篇关于将 Windows 窗体吸附到桌面屏幕边缘的文章。

Sample Image - SnapTo.png

引言

本文演示了如何在您的应用程序中添加吸附屏幕功能。此功能允许您将窗口拖动到屏幕边缘附近,并使窗口自动被拉向该边缘,就像磁铁一样。这里已经有一个不错的非托管 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。

© . All rights reserved.