環境
C# - Winodws Form Application (Visual Studio 2017 , .NET Framework 4.5)
タイトルバーの無いフォームに自作タイトルバーを作る
これが果たしておしゃれかどうかはおいといて、こういったタイトルバーのないフォームを作った場合、最大化・最小化は不要、終了はthis.Close();
でいいとして、地味に面倒くさいのが 掴んで移動ができないこと です。
実装方法はいろいろあるとは思いますが、ここでは、Win32APIを使って、上側にあるピクチャボックスをタイトルバーとして認識させたいと思います。
‥‥といっても、この手法自体は.NETの前のVisualBasicの時代から通用するものであって、軽く調べても、dobon.netさんを始め、いくらでも記載が見つかります。
この記事では、昔調べた手法が今も使えるという意味合いで記しておきます。
(というか.NET内でやる方法がご存知でしたら教えてください)
実装方針
使うWin32APIは、ReleaseCapture
とSendMessage
です。
- まずピクチャボックスへのマウス押下に対して、押下状態を解除(
ReleaseCapture
)し、マウスの入力をキャンセルします。 - 次に、ウインドウメッセージを送信(
SendMessage
)し、タイトルバーにマウスが押されたことを通知します。
これにより、「ピクチャボックスを掴む」=「タイトルバーを掴んだ扱い」として扱われます。
サンプル
ピクチャボックスpicHeaderを貼りつけ、MouseDown
イベントを作ります。
//using System.Runtime.InteropServices;
private void picHeader_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Win32Api.MouseLeftDownOnFormTitleBar(this);
}
}
private static class Win32Api
{
#region SendMessage
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SendMessage(IntPtr hWnd, int Msg, IntPtr wParam, IntPtr lParam);
#endregion
#region ReleaseCapture
[DllImport("user32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool ReleaseCapture();
#endregion
#region MouseLeftDownOnFormTitleBar
/// <summary>
/// タイトルバーを左クリックする
/// </summary>
/// <param name="frm">対象のフォーム</param>
public static void MouseLeftDownOnFormTitleBar(System.Windows.Forms.Form frm)
{
ReleaseCapture();
SendMessage(frm.Handle, (int)0x00A1, new IntPtr(0x0002), IntPtr.Zero);
}
#endregion
}
SendMessage
の引数である0x00A1
と0x0002
が、それぞれWM_NCLBUTTONDOWN
=マウス左ボタン押下、HT_CAPTION
=タイトルバー部分を意味しています。定数にしておくのが正しいとは思います。
余談
趣味でやってると、オリジナルの見た目のフォームを作りたい時ってあると思います。そういう時に任意のコントロールをタイトルバーに出来ると表現の幅が広がります。
これ自体は結構有用なコードだと思うのですが、最近じゃFrameworkの方も優秀で、あえてWin32APIを使うべきケースも少ないもので、そんなことでAPIをわざわざ勉強するのもなぁって感じですね。
実際、SendMessage
の他の引数とかを使ってやりたいことなどはなかなか思いつかないし、そんなわけでこのロジックそのものをタイトルバー処理専用と割り切って私は使っています。
独学のため正確でない可能性があります。
(っ・x・)っ きゅ