DOBON.NET プログラミング道: .NET Framework, VB.NET, C#, Visual Basic, Visual Studio, インストーラ, ...

フォームの位置や大きさが変更されたことを知る

ここでは、フォーム(ウィンドウ)が移動(位置が変更)したり、フォームの大きさ(サイズ)が変更されたことを知る方法について説明します。

フォームの大きさが変化したことを知る

フォームの大きさが変更されると、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のごく簡単な例も示しています。

VB.NET
コードを隠すコードを選択
'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
C#
コードを隠すコードを選択
//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の両方を使用していますが、実際にはどちらか一方のみにしてください。

VB.NET
コードを隠すコードを選択
'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
C#
コードを隠すコードを選択
//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メソッドをオーバーライドしてこれらのメッセージを監視することで、フォームが移動中か、サイズ変更中かを知ることができます。

なおこれらのメッセージは、フォームの位置や大きさをコードで変更した時には送られてきません。

フォームが移動中、あるいはサイズ変更中である時、フォームの位置と大きさを表示する例を示します。このコードは、フォームクラス内に記述してください。

VB.NET
コードを隠すコードを選択
'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
C#
コードを隠すコードを選択
//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);
}

注意:この記事では、基本的な事柄の説明が省略されているかもしれません。初心者の方は、特に以下の点にご注意ください。

  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。
  • コードの先頭に記述されている「Imports ??? がソースファイルの一番上に書かれているものとする」(C#では、「using ???; がソースファイルの一番上に書かれているものとする」)の意味が分からないという方は、こちらをご覧ください。
  • .NET Tipsをご利用いただく際は、注意事項をお守りください。