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

DOBON.NET

タイトルバーのないフォームを移動できるようにする

タイトルバーを持たないフォームをマウスで移動させる方法です。ここではWin32 APIを使用しない方法を紹介します。

マウスイベントによる方法

まずは、最も基本的なやり方です。次のコードでは、単純にフォーム(Form1)上でマウスの左ボタンが押され、移動させたことを感知することにより処理しています。

[VB.NET]
'マウスのクリック位置を記憶
Private mousePoint As Point

'マウスのボタンが押されたとき
Private Sub Form1_MouseDown(ByVal sender As Object, _
  ByVal e As System.Windows.Forms.MouseEventArgs) _
  Handles MyBase.MouseDown
    If (e.Button And MouseButtons.Left) = MouseButtons.Left Then
        '位置を記憶する
        mousePoint = New Point(e.X, e.Y)
    End If
End Sub

'マウスが動いたとき
Private Sub Form1_MouseMove(ByVal sender As Object, _
  ByVal e As System.Windows.Forms.MouseEventArgs) _
  Handles MyBase.MouseMove
    If (e.Button And MouseButtons.Left) = MouseButtons.Left Then
        Me.Left += e.X - mousePoint.X
        Me.Top += e.Y - mousePoint.Y
        'または、つぎのようにする
        'Me.Location = New Point( _
        '    Me.Location.X + e.X - mousePoint.X, _
        '    Me.Location.Y + e.Y - mousePoint.Y)
    End If
End Sub
[C#]
//マウスのクリック位置を記憶
private Point mousePoint;

//マウスのボタンが押されたとき
private void Form1_MouseDown(object sender,
    System.Windows.Forms.MouseEventArgs e)
{
    if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
    {
        //位置を記憶する
        mousePoint = new Point(e.X, e.Y);
    }
}

//マウスが動いたとき
private void Form1_MouseMove(object sender,
    System.Windows.Forms.MouseEventArgs e)
{
    if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
    {
        this.Left += e.X - mousePoint.X;
        this.Top += e.Y - mousePoint.Y;
        //または、つぎのようにする
        //this.Location = new Point(
        //    this.Location.X + e.X - mousePoint.X,
        //    this.Location.Y + e.Y - mousePoint.Y);
    }
}

上の例ではフォーム上にあるコントロールの上でマウスのボタンを押してドラッグしてもウィンドウは移動しません。コントロール上のドラッグでも移動できるようにするには、そのコントロールのMouseDownおよびMouseMoveイベントハンドラにForm1_MouseDownおよびForm1_MouseMoveを追加します。例えばForm1にPictureBox1オブジェクトがあり、PictureBox1上でマウスボタンを押してドラッグを開始してもForm1が移動できるようにするには次のようにします。

[VB.NET]
Private mousePoint As Point

Private Sub Form1_MouseDown(ByVal sender As Object, _
        ByVal e As System.Windows.Forms.MouseEventArgs) _
        Handles MyBase.MouseDown, PictureBox1.MouseDown
    '(上の例と同じため省略)
End Sub

Private Sub Form1_MouseMove(ByVal sender As Object, _
        ByVal e As System.Windows.Forms.MouseEventArgs) _
        Handles MyBase.MouseMove, PictureBox1.MouseMove
    '(上の例と同じため省略)
End Sub
[C#]
private void Form1_Load(object sender, System.EventArgs e)
{
    PictureBox1.MouseDown +=
        new MouseEventHandler(Form1_MouseDown);
    PictureBox1.MouseMove +=
        new MouseEventHandler(Form1_MouseMove);
}

//マウスのクリック位置を記憶
private Point mousePoint;

//マウスのボタンが押されたとき
private void Form1_MouseDown(object sender,
    System.Windows.Forms.MouseEventArgs e)
{
    //(上の例と同じため省略)
}

//マウスが動いたとき
private void Form1_MouseMove(object sender,
    System.Windows.Forms.MouseEventArgs e)
{
    //(上の例と同じため省略)
}

WndProcをオーバーライドする方法

次は、フォームのWndProcメソッドをオーバーライドする方法です。この方法では、あたかもタイトルバーをマウスで移動させているふりをして、フォームを移動させています。

[VB.NET]
Protected Overrides Sub WndProc(ByRef m As Message)
    MyBase.WndProc(m)

    Const WM_NCHITTEST As Integer = &H84
    Const HTCLIENT As Integer = 1
    Const HTCAPTION As Integer = 2

    'マウスポインタがクライアント領域内にあるか
    If m.Msg = WM_NCHITTEST And m.Result.ToInt32() = HTCLIENT Then
        'マウスがタイトルバーにあるふりをする
        m.Result = New IntPtr(HTCAPTION)
    End If
End Sub
[C#]
protected override void WndProc(ref Message m)
{
    base.WndProc (ref m);

    const int WM_NCHITTEST = 0x84;
    const int HTCLIENT = 1;
    const int HTCAPTION = 2;

    //マウスポインタがクライアント領域内にあるか
    if ((m.Msg == WM_NCHITTEST) &&
        (m.Result.ToInt32() == HTCLIENT))
    {
        //マウスがタイトルバーにあるふりをする
        m.Result = (IntPtr) HTCAPTION;
    }
}

この方法もはじめの方法と同様、このままでは、フォーム上にあるコントロールの上でマウスのボタンを押して移動させようとしてもウィンドウは移動しません。

  • 履歴:
  • 2006/9/20 コメントにお寄せいただいたご指摘により、一番始めのコードを書き直しました。

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

  • イベントハンドラの意味が分からない、C#のコードをそのまま書いても動かないという方は、こちらをご覧ください。