ここでは、フォーム(ウィンドウ)が移動(位置が変更)したり、フォームの大きさ(サイズ)が変更されたことを知る方法について説明します。
フォームの大きさが変更されると、SizeChangedイベントとResizeイベントが発生します。SizeChangedイベントとResizeイベントの違いは特にないようですので(「So what IS the difference between the Resize and the SizeChanged events?」参照)、どちらを使用してもよいでしょう。
補足:イベントが発生する順番は、Resize、SizeChangedとなります。
ユーザーがフォームの枠をドラッグして大きさを変更する時、ドラッグを開始した時にResizeBeginイベントが、ドロップした時にResizeEndイベントが発生します。これらのイベントは、.NET Framework 2.0以降で使用できます。
ResizeBeginとResizeEndイベントは、ユーザーがフォームのキャプションバーをドラッグして移動させた時にも発生します。
補足:コントロールボックスのメニューから「移動」や「サイズ変更」を選択した時もこれらのイベントが発生します。
補足:ユーザーがフォームのサイズを変更した時イベントの発生する順番は、ResizeBegin、Resize、SizeChanged、ResizeEndとなります。
以下のサンプルでは、フォームのサイズが変更された時に、フォームのサイズを表示しています。SizeChangedとResizeの両方を使用していますが、実際にはどちらか一方のみにしてください。また、ResizeBeginとResizeEndのごく簡単な例も示しています。
'SizeChangedイベントハンドラ Private Sub Form1_SizeChanged(sender As Object, e As EventArgs) _ Handles MyBase.SizeChanged Dim c As Control = DirectCast(sender, Control) Console.WriteLine("フォームのサイズが{0}x{1}に変更されました", _ c.Width, c.Height) End Sub 'Resizeイベントハンドラ Private Sub Form1_Resize(sender As Object, e As EventArgs) _ Handles MyBase.Resize Dim c As Control = DirectCast(sender, Control) Console.WriteLine("フォームのサイズが{0}x{1}に変更されました", _ c.Width, c.Height) End Sub 'ResizeBeginイベントハンドラ Private Sub Form1_ResizeBegin(sender As Object, e As EventArgs) _ Handles MyBase.ResizeBegin Console.WriteLine("ユーザーがフォームの移動またはサイズ変更を開始しました") End Sub 'ResizeEndイベントハンドラ Private Sub Form1_ResizeEnd(sender As Object, e As EventArgs) _ Handles MyBase.ResizeEnd Console.WriteLine("ユーザーがフォームの移動またはサイズ変更を終了しました") End Sub
//SizeChangedイベントハンドラ private void Form1_SizeChanged(object sender, EventArgs e) { Control c = (Control)sender; Console.WriteLine("フォームのサイズが{0}x{1}に変更されました", c.Width, c.Height); } //Resizeイベントハンドラ private void Form1_Resize(object sender, EventArgs e) { Control c = (Control)sender; Console.WriteLine("フォームのサイズが{0}x{1}に変更されました", c.Width, c.Height); } //ResizeBeginイベントハンドラ private void Form1_ResizeBegin(object sender, EventArgs e) { Console.WriteLine( "ユーザーがフォームの移動またはサイズ変更を開始しました"); } //ResizeEndイベントハンドラ private void Form1_ResizeEnd(object sender, EventArgs e) { Console.WriteLine( "ユーザーがフォームの移動またはサイズ変更を終了しました"); }
フォームが移動すると、LocationChangedイベントとMoveイベントが発生します。LocationChangedイベントとMoveイベントの違いも、特にないようです。
補足:イベントが発生する順番は、Move、LocationChangedとなります。
先述した通り、ユーザーがフォームを移動させた時は、ResizeBeginイベントとResizeEndイベントも発生します。
補足:ユーザーがフォームを移動した時イベントの発生する順番は、ResizeBegin、Move、LocationChanged、ResizeEndとなります。また、ユーザーがフォームのサイズを変更した時に移動もした場合は、ResizeBegin、Move、LocationChanged、Resize、SizeChanged、ResizeEndの順番になります。
以下のサンプルでは、フォームが移動した時に、フォームの位置を表示しています。LocationChangedとMoveの両方を使用していますが、実際にはどちらか一方のみにしてください。
'LocationChangedイベントハンドラ Private Sub Form1_LocationChanged(sender As Object, e As EventArgs) _ Handles MyBase.LocationChanged Dim c As Control = DirectCast(sender, Control) Console.WriteLine("フォームが({0},{1})に移動しました", c.Left, c.Top) End Sub 'Moveイベントハンドラ Private Sub Form1_Move(sender As Object, e As EventArgs) _ Handles MyBase.Move Dim c As Control = DirectCast(sender, Control) Console.WriteLine("フォームが({0},{1})に移動しました", c.Left, c.Top) End Sub
//LocationChangedイベントハンドラ private void Form1_LocationChanged(object sender, EventArgs e) { Control c = (Control)sender; Console.WriteLine("フォームが({0},{1})に移動しました", c.Left, c.Top); } //Moveイベントハンドラ private void Form1_Move(object sender, EventArgs e) { Control c = (Control)sender; Console.WriteLine("フォームが({0},{1})に移動しました", c.Left, c.Top); }
補足:SizeChanged、Resize、LocationChanged、Moveイベントは、ウィンドウメッセージWM_WINDOWPOSCHANGEDまたはWM_MOVEが送られてきて、サイズまたは位置が変更されている時に発生するようです。また、ResizeBeginはWM_ENTERSIZEMOVE、ResizeEndはWM_EXITSIZEMOVEが送られてきた時に発生するようです。
フォームがユーザーによって移動させられている最中は、ウィンドウメッセージWM_MOVINGが送られてきます。また、フォームがユーザーによってサイズ変更させられている最中は、WM_SIZINGが送られてきます。フォームのWndProcメソッドをオーバーライドしてこれらのメッセージを監視することで、フォームが移動中か、サイズ変更中かを知ることができます。
なおこれらのメッセージは、フォームの位置や大きさをコードで変更した時には送られてきません。
フォームが移動中、あるいはサイズ変更中である時、フォームの位置と大きさを表示する例を示します。このコードは、フォームクラス内に記述してください。
'using System.Security.Permissions; <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 'WM_SIZING If m.Msg = WM_SIZING Then '現在のフォームの範囲を取得する Dim rect As Rectangle = DirectCast( _ System.Runtime.InteropServices.Marshal.PtrToStructure( _ m.LParam, GetType(Rectangle)), Rectangle) 'rect.Widthとrect.Heightはフォーム右下の座標になっている 'よって、幅と高さを取得するには、次のようにする rect.Width -= rect.Left rect.Height -= rect.Top '結果を表示する Console.WriteLine("リサイズ中...({0})", rect) 'WM_MOVING ElseIf m.Msg = WM_MOVING Then Dim rect As Rectangle = DirectCast( _ System.Runtime.InteropServices.Marshal.PtrToStructure( _ m.LParam, GetType(Rectangle)), Rectangle) rect.Width -= rect.Left rect.Height -= rect.Top Console.WriteLine("移動中... ({0})", rect) End If MyBase.WndProc(m) End Sub
//using System.Security.Permissions; [SecurityPermission(SecurityAction.Demand, Flags = SecurityPermissionFlag.UnmanagedCode)] protected override void WndProc(ref Message m) { const int WM_SIZING = 0x214; const int WM_MOVING = 0x216; //WM_SIZING if (m.Msg == WM_SIZING) { //現在のフォームの範囲を取得する Rectangle rect = (Rectangle) System.Runtime.InteropServices.Marshal.PtrToStructure( m.LParam, typeof(Rectangle)); //rect.Widthとrect.Heightはフォーム右下の座標になっている //よって、幅と高さを取得するには、次のようにする rect.Width -= rect.Left; rect.Height -= rect.Top; //結果を表示する Console.WriteLine("リサイズ中...({0})", rect); } //WM_MOVING else if (m.Msg == WM_MOVING) { Rectangle rect = (Rectangle) System.Runtime.InteropServices.Marshal.PtrToStructure( m.LParam, typeof(Rectangle)); rect.Width -= rect.Left; rect.Height -= rect.Top; Console.WriteLine("移動中... ({0})", rect); } base.WndProc(ref m); }