例えば、フォームがデスクトップ領域の外に出ないようにしたり、フォームが画面の上部にくっついたようにしか移動できないようにしたり、垂直、あるいは水平にしか移動できないようにするといったように、フォームが特定の箇所にしか移動できないようにする方法を紹介します。
簡単なのは、「フォームの位置や大きさが変更されたことを知る」と「フォームの位置と大きさを取得、変更する」で紹介している方法を使って、フォームが移動した直後にフォームの位置を修正するという方法です。
以下の例では、LocationChangedイベントを使用して、フォームがプライマリディスプレイの作業領域の外に移動できないようにしています。
'LocationChangedイベントハンドラ Private Sub Form1_LocationChanged(sender As Object, e As EventArgs) _ Handles MyBase.LocationChanged 'フォームが最小化、最大化状態の時は無視 If Me.WindowState <> FormWindowState.Normal Then Return End If 'フォームが移動できる範囲 Dim area As Rectangle = Screen.PrimaryScreen.WorkingArea 'フォームの大きさが移動できる範囲より大きくならないようにする If area.Width < Me.Width Then Me.Width = area.Width End If If area.Height < Me.Height Then Me.Height = area.Height End If 'フォームの左の位置を修正 If Me.Left < area.Left Then Me.Left = area.Left ElseIf area.Left + area.Width < Me.Left + Me.Width Then Me.Left = area.Left + area.Width - Me.Width End If 'フォームの上の位置を修正 If Me.Top < area.Top Then Me.Top = area.Top ElseIf area.Top + area.Height < Me.Top + Me.Height Then Me.Top = area.Top + area.Height - Me.Height End If End Sub
//LocationChangedイベントハンドラ private void Form1_LocationChanged(object sender, EventArgs e) { //フォームが最小化、最大化状態の時は無視 if (this.WindowState != FormWindowState.Normal) { return; } //フォームが移動できる範囲 Rectangle area = Screen.PrimaryScreen.WorkingArea; //フォームの大きさが移動できる範囲より大きくならないようにする if (area.Width < this.Width) { this.Width = area.Width; } if (area.Height < this.Height) { this.Height = area.Height; } //フォームの左の位置を修正 if (this.Left < area.Left) { this.Left = area.Left; } else if (area.Left + area.Width < this.Left + this.Width) { this.Left = area.Left + area.Width - this.Width; } //フォームの上の位置を修正 if (this.Top < area.Top) { this.Top = area.Top; } else if (area.Top + area.Height < this.Top + this.Height) { this.Top = area.Top + area.Height - this.Height; } }
上記の方法では、ユーザーがフォームを移動した直後にフォームが再び移動するため、見た目はよくありません。「フォームの位置や大きさが変更されたことを知る」で紹介しているWM_MOVINGを使用すれば、この問題は解消されます。
この方法は、ユーザーがフォームを移動させる場合にだけ有効です。ユーザーがフォームをリサイズする場合も考慮するなら、WM_SIZINGも使用する必要があります。また、プログラムによってフォームを移動させる場合も考慮するのであれば、上記LocationChangedイベントを使用した方法も併用してください。
以下の例では、この方法を使ってフォームがプライマリディスプレイの作業領域の外に移動できないようにしています。ここではユーザーがフォームをリサイズすることも考慮して、WM_MOVINGとWM_SIZINGを監視しています。
'Imports System.Runtime.InteropServices 'Imports System.Security.Permissions <StructLayout(LayoutKind.Sequential)> _ Private Structure RECT Private _left As Integer Private _top As Integer Private _right As Integer Private _bottom As Integer Public Property Left() As Integer Get Return _left End Get 'Widthを維持してLeftを変更 Set(value As Integer) _right = _right - _left + value _left = value End Set End Property Public Property Top() As Integer Get Return _top End Get Set(value As Integer) _bottom = _bottom - _top + value _top = value End Set End Property Public Property Width() As Integer Get Return _right - _left End Get Set(value As Integer) _right = _left + value End Set End Property Public Property Height() As Integer Get Return _bottom - Top End Get Set(value As Integer) _bottom = Top + value End Set End Property End Structure <SecurityPermission(SecurityAction.Demand, _ Flags:=SecurityPermissionFlag.UnmanagedCode)> _ Protected Overrides Sub WndProc(ByRef m As Message) Const WM_SIZING As Integer = &H214 Const WM_MOVING As Integer = &H216 If m.Msg = WM_MOVING OrElse m.Msg = WM_SIZING Then 'フォームが移動できる範囲 Dim area As Rectangle = Screen.PrimaryScreen.WorkingArea 'フォームの位置を取得 Dim rect As RECT = CType( _ System.Runtime.InteropServices.Marshal.PtrToStructure( _ m.LParam, GetType(RECT)), RECT) 'フォームの大きさが移動できる範囲より大きくならないようにする If area.Width < rect.Width Then rect.Width = area.Width End If If area.Height < rect.Height Then rect.Height = area.Height End If 'フォームの左の位置を修正 If rect.Left < area.Left Then rect.Left = area.Left ElseIf area.Left + area.Width < rect.Left + rect.Width Then rect.Left = area.Left + area.Width - rect.Width End If 'フォームの上の位置を修正 If rect.Top < area.Top Then rect.Top = area.Top ElseIf area.Top + area.Height < rect.Top + rect.Height Then rect.Top = area.Top + area.Height - rect.Height End If 'フォームの位置を設定 System.Runtime.InteropServices.Marshal.StructureToPtr( _ rect, m.LParam, True) End If MyBase.WndProc(m) End Sub
//using System.Runtime.InteropServices; //using System.Security.Permissions; [StructLayout(LayoutKind.Sequential)] private struct RECT { private int _left; private int _top; private int _right; private int _bottom; public int Left { get { return _left; } //Widthを維持してLeftを変更 set { _right = _right - _left + value ; _left = value; } } public int Top { get { return _top; } set { _bottom = _bottom - _top + value; _top = value; } } public int Width { get { return _right - _left; } set { _right = _left + value; } } public int Height { get { return _bottom - Top; } set { _bottom = Top + value; } } } [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { const int WM_SIZING = 0x214; const int WM_MOVING = 0x216; if (m.Msg == WM_MOVING || m.Msg == WM_SIZING) { //フォームが移動できる範囲 Rectangle area = Screen.PrimaryScreen.WorkingArea; //フォームの位置を取得 RECT rect = (RECT) System.Runtime.InteropServices.Marshal.PtrToStructure( m.LParam, typeof(RECT)); //フォームの大きさが移動できる範囲より大きくならないようにする if (area.Width < rect.Width) { rect.Width = area.Width; } if (area.Height < rect.Height) { rect.Height = area.Height; } //フォームの左の位置を修正 if (rect.Left < area.Left) { rect.Left = area.Left; } else if (area.Left + area.Width < rect.Left + rect.Width) { rect.Left = area.Left + area.Width - rect.Width; } //フォームの上の位置を修正 if (rect.Top < area.Top) { rect.Top = area.Top; } else if (area.Top + area.Height < rect.Top + rect.Height) { rect.Top = area.Top + area.Height - rect.Height; } //フォームの位置を設定 System.Runtime.InteropServices.Marshal.StructureToPtr( rect, m.LParam, true); } base.WndProc(ref m); }