Windowsフォーム画面の最上部に表示される「タイトル・バー(別名:キャプション・バー)」には、小さなアイコン(例えば次の画面の(1))が左端に表示され、それに続いてタイトル文字列があり、右端には[最小化]ボタン(3)、[最大化/元に戻す]ボタン(4)、[閉じる]ボタン(5)がある。
Windowsフォームのタイトル・バー
タイトル・バーを右クリックすると、(6)のメニューが表示される。
(1)小さなアイコン。ここを左クリックすると、(6)のメニューが表示される。
(2)タイトル文字列。
(3)[最小化]ボタン。
(4)[最大化]ボタン。最大化されている場合は、[元に戻す]ボタンが表示される。
(5)[閉じる]ボタン。
(6)コントロールボックス。システム・メニューとも呼ばれる。
(7)[閉じる]メニュー項目。
このうち、右側の[最小化]ボタンを無効にするにはフォームのMinimizeBoxプロパティを、[最大化]ボタンを無効にするにはMaximizeBoxプロパティを、それぞれfalseに設定すればよい。しかし一番右端の[閉じる]ボタンを無効にするためのプロパティは用意されていない。では、この[閉じる]ボタンを無効にするにはどうすればよいのだろうか。
ControlBoxプロパティによる[閉じる]ボタンの無効化
1つの解決策としては、フォームのControlBoxプロパティをfalseにすればよい。ControlBoxプロパティは、コントロールボックス(別名:システム・メニュー)を有効(true)/無効(false)にするためのプロパティである。ただし、このControlBoxプロパティをfalseにすれば、コントロールボックスだけでなく、左端のアイコン、[閉じる]ボタン、[最小化]ボタン、[最大化/元に戻す]ボタンなど、すべてのボタンとアイコンが非表示になってしまう。このとき、タイトル・バーを右クリックしてもコントロールボックス(システム・メニュー)は表示されない。
コントロールボックスを無効に設定したWindowsフォーム
タイトル・バーにはタイトル文字列が表示されているだけで、小さなアイコン、[最小化]ボタン、[最大化/元に戻す]ボタン、[閉じる]ボタンが非表示になっている。タイトル・バーを右クリックしてもコントロールボックス(システム・メニュー)は表示されない。
しかしこのようにすべてのボタンを非表示にするのではなく、無効化するのは[閉じる]ボタンだけで、そのほかの小さなアイコン、[最大化/元に戻す]ボタン、[最小化]ボタンはそのまま残しておきたい場合もあるだろう。そのような場合は、Win32 APIを使う必要がある。
Win32 APIを使用した[閉じる]ボタンの無効化
Win32 APIで[閉じる]ボタンの無効化を実装するには、フォームのコントロールボックス(システム・メニュー)を取得して、その中の[閉じる]メニュー項目(先ほどの画面「Windowsフォームのタイトル・バー」の(7))を削除すればよい。そうすれば、タイトル・バーの[閉じる]ボタンも自動的に無効化されるようになっている。
具体的には、Win32 APIのGetSystemMenu関数を呼び出してシステム・メニューのハンドルを取得し、RemoveMenu関数を呼び出してシステム・メニューから[閉じる]メニュー項目を削除する。
これらの関数の構文について簡単に説明する。なお、これらの関数のより詳しい説明は、MSDNの「プラットフォームSDK」を参照していただきたい。
IntPtr GetSystemMenu(IntPtr hWnd, UInt32 bRevert)
GetSystemMenu関数の第1パラメータには、ウィンドウ・ハンドル(ウィンドウを識別するためにシステムによって割り当てられる番号)を指定する。このウィンドウ・ハンドルは、フォームのHandleプロパティに格納されている。第2パラメータには、コントロールボックスをデフォルトに戻す(初期化する)かどうかを指定する。本稿のようにコントロールボックスを取得する場合には「0」を指定する。削除した[閉じる]ボタンを復活させるには、このパラメータに「1」を指定してコントロールボックスを初期化すればよい。関数の戻り値には、システム・メニューのハンドル(識別番号)が返される。
UInt32 RemoveMenu(IntPtr hMenu, UInt32 nPosition, UInt32 wFlags)
RemoveMenu関数の第1パラメータにはメニューのハンドルを指定する。第2パラメータにはメニュー項目のIDを指定する。[閉じる]ボタンのIDは「SC_CLOSE(0x0000F060)」である。第3パラメータには「MF_BYCOMMAND(0x00000000)」を指定する。このMF_BYCOMMANDは、第2パラメータが「ID指定」であることを意味する。
ショートカット・キーによりフォームが閉じられるのを防止する
以上のWin32 API関数を使えば[閉じる]ボタンだけを無効化できるが、これだけではまだ完璧ではない。Windowsシステムには、アプリケーションを閉じるためのショートカット・キー「Altキー+F4キー」というものが存在する。このショートカット・キーを使えば、[閉じる]ボタンが無効であっても、右端にあった[閉じる]ボタンを押したのと同じようにWindowsフォームが閉じられてしまう。
よって、ショートカット・キーによりフォームが閉じられるのを阻止しなければ、[閉じる]ボタンを無効にした意味がない。次にその方法を解説しよう。ちなみに、ControlBoxプロパティをfalseにした場合も、アプリケーションを閉じるためのショートカット・キーは有効である。このため、その場合にも同じように次の処理が必要になるので注意していただきたい。
ショートカット・キーによってWindowsフォームが閉じられるのを防止するには、フォームが閉じられる直前に発生するClosingイベントのハンドラ・メソッドをまず追加する。そして、Closingイベント・ハンドラの第2パラメータであるCancelEventArgsクラス(System.ComponentModel名前空間)のオブジェクトのCancelプロパティにtrueを設定するだけでよい。
[閉じる]ボタンのみを無効化したサンプル・プログラム
以上の内容を実装したサンプル・プログラムを次に示す。このプログラムでは、フォーム上に配置した[終了]ボタンがクリックされた場合にのみフォームを閉じるようにするため、フラグによりClosingイベント・ハンドラでの処理を制御している。
using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace WindowsApplication1
{
// Windowsフォームのクラス
public class Form1 : System.Windows.Forms.Form
{
private System.Windows.Forms.Button button1;
private System.ComponentModel.Container components = null;
// コンストラクタ(初期化処理などを呼び出す)
public Form1()
{
// 初期化処理
InitializeComponent();
// コントロールボックスの[閉じる]ボタンの無効化
IntPtr hMenu = GetSystemMenu(this.Handle, 0);
RemoveMenu(hMenu, SC_CLOSE, MF_BYCOMMAND);
}
// Win32 APIのインポート
[ DllImport("USER32.DLL") ]
private static extern IntPtr GetSystemMenu(IntPtr hWnd, UInt32 bRevert);
[ DllImport("USER32.DLL") ]
private static extern UInt32 RemoveMenu(IntPtr hMenu, UInt32 nPosition, UInt32 wFlags);
// [閉じる]ボタンを無効化するための値
private const UInt32 SC_CLOSE = 0x0000F060;
private const UInt32 MF_BYCOMMAND = 0x00000000;
// 後処理(使用されているリソースの解放など)
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
// 初期化処理(コントロール属性の設定など)
private void InitializeComponent()
{
// [閉じる]ボタンの追加
this.button1 = new System.Windows.Forms.Button();
// フォームとコントロールの属性を調整するため、
// フォームのレイアウト処理を一時停止する
this.SuspendLayout();
//
// button1
//
this.button1.Location = new System.Drawing.Point(104, 136);
this.button1.Name = "button1";
this.button1.TabIndex = 0;
this.button1.Text = "終了";
this.button1.Click += new System.EventHandler(this.button1_Click);
//
// Form1
//
this.AutoScaleBaseSize = new System.Drawing.Size(5, 12);
this.ClientSize = new System.Drawing.Size(292, 182);
this.Controls.Add(this.button1);
this.Name = "Form1";
this.Text = "Form1";
this.Closing +=
new System.ComponentModel.CancelEventHandler(this.Form1_Closing);
// フォームとコントロールの初期化が終わったので、
// レイアウト処理の一時停止を解除する
this.ResumeLayout(false);
}
// アプリケーションのメイン・エントリ・ポイント
[STAThread]
static void Main()
{
Application.Run(new Form1());
}
// [終了]ボタンが押されたかどうかの終了フラグ
private bool bFinished = false;
// [終了]ボタンを押されたとき、Windowsフォームを閉じる
private void button1_Click(object sender, System.EventArgs e)
{
bFinished = true; // 終了のためのフラグを立てる
this.Close(); // Windowsフォームを閉じる
}
// Windowsフォームが閉じられる直前に呼ばれるイベント・ハンドラ
private void Form1_Closing(object sender, System.ComponentModel.CancelEventArgs e)
{
// 終了フラグを立ってなければ、フォームが閉じられるのを阻止
if (bFinished == true)
{
e.Cancel = false;
}
else
{
e.Cancel = true;
}
}
}
}
これを実行すると、表示されるフォームは次のような画面になる。
[閉じる]ボタンだけが無効化されているWindowsフォーム
タイトル・バーは[閉じる]ボタンのみが無効化され、コントロールボックス、アイコン、[最小化]ボタン、[最大化/元に戻す]ボタンはそのまま残されている。さらに、Windowsシステムのシュートカット「Altキー+F4キー」を使ってもWindowsフォームが閉じられないようになっている。Windowsフォームを閉じるには、必ず[終了]ボタンを押さなければならない。
なお、.NETプログラムからWin32 APIを呼び出す方法については、別稿「TIPS:Win32 APIやDLL関数を呼び出すには?」を参照していただきたい。
カテゴリ:Windowsフォーム 処理対象:ダイアログ・ボックス
使用ライブラリ:Formクラス(System.Windows.Forms名前空間)
使用ライブラリ:CancelEventArgsクラス(System.ComponentModel名前空間)
関連TIPS:Win32 APIやDLL関数を呼び出すには?
Copyright© Digital Advantage Corp. All Rights Reserved.