お世話になります。
Windows XP Pro SP3 / Visual Studio 2008 SP1
C++/CLI / Windowsフォームアプリケーションでアプリケーションを作成しています。
フォーム1(Form1 : System::Windows::Froms::Form)に
テキストボックス1(textBox1 : System::Windows::Forms::TextBox)と
ボタン1(button1 : System::Windows::Forms::Button)を配置しています。
テキストボックス1のLeaveイベントハンドラと
ボタン1のClickイベントハンドラを追加し、下のようにしています。
private:
System::Void textBox1_Leave(System::Object^ sender, System::EventArgs^ e) {
MessageBox::Show(Leaveイベントが発生しました。);
}
private:
System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) {
textBox1->Text = button1をクリックしました。;
}
ビルド後、実行し、テキストボックス1にフォーカスを当てた状態で
ボタン1をクリックします。
メッセージボックスが表示されるのでOKボタンをクリックします。
その後、ボタン1のクリックイベントハンドラが実行されることを
期待していたのですがメッセージボックスを閉じた後、
何も実行されません(ボタン1にフォーカスは移りますが)。
テキストボックス1がフォーカスを失うのがボタン1をクリックしたタイミング
だけではないのでテキストボックス1のLeaveイベントハンドラ内で
ボタン1のClickイベントを設定するわけにもいかず、困っています。
メッセージボックスを閉じた後、ボタン1のクリックイベントハンドラを
実行させる、というか発生するはずだったイベントをちゃんと発生させる
にはどうしたらいいのでしょうか。
フォーカス移動イベントで、さらにフォーカスが移るような挙動をさせてはいけませ
ん。
LeaveイベントでMessageBoxを表示させなければどうなりますか?
noriさま、maruさま回答ありがとうございます。
noriさま
> フォーカス移動イベントで、さらにフォーカスが移るような挙動をさせてはいけませ
> ん。
今、テキストボックスからフォーカスがはずれるタイミングでその内容をチェックし、
チェックの結果によってはメッセージボックスをYES/NO/CANCELボタン付きで表示し、
ユーザによってキャンセルがクリックされた場合はフォーカス移動をキャンセル、
それ以外なら継続(例えばボタン1のクリックイベントハンドラの内容を実行など)
という動作を実装したいのですが、Leaveイベント以外でこの動作をさせるには
どうすればいいのでしょうか。
maruさま、
> LeaveイベントでMessageBoxを表示させなければどうなりますか?
ボタン1のクリックイベントが実行され、テキストボックス1に
button1をクリックしました。
と表示されます。
Leaveイベントでメッセージを表示しなければならないのか、という意味でしたら、
上に書かせていただいた回答と同じになります。
メッセージボックスでYes/Noを選択する必要性がわからないので有効な回答かどうか
わからないのですが、テキストボックスの内容をチェックしたいというのであれば、
フォーカスを失った時に内容をチェックして、入力値が異常な場合はその旨をメッセー
ジボックスで表示し、(必要ならば、テキストボックスの変更しなければならない文字
列を選択状態にする)正常ならなメッセージボックスを表示しない。
Yes/Noを選択するのは、ボタンクリックイベントで実行する。
というのはどうですか?
あなたの実装では正常な入力であっても、フォーカスが移動したときに毎回メッセー
ジボックスで確認を求められ、使いにくいアプリケーションになると思います。
私の案でも、フォーカス移動時には正常値が入力されている必要があるので、テキス
トボックスに正常値を入力するまで、ダイアログを終わることができないという問題
が発生します。通常、テキストボックスの内容の検査は必要になるまで実行しません。
(ダイアログボックス自体をキャンセルで終了する場合、検査する必要はない!)
TextBox.Validatingを調べて見てください。
とりあえず何が起きているかだけ解説。
> 起こるはずのイベントが起こらない
1、Button 上で WM_LBUTTONDOWN(この後、Button 上で WM_LBUTTONUP されれば
ボタンクリック完了となる)
2、クリック完了を検知するため Button がマウス入力をキャプチャする
3、TextBox がフォーカスを消失するので WM_KILLFOCUS が通知される
4、TextBox::Leave() で MessageBox 表示
5、MessageBox 表示に伴い WM_CANCELMODE が投げられる
6、[5] に伴い Button がマウス入力をキャプチャしていた状態が解除
7、[6] に伴い Button のクリック関連処理が中止
8、MessageBox 終了
9、TextBox::Leave() 終了
システム側から見れば、プログラム側が [4] を行った時点でボタンのクリックイベント
の中止に(仕様に理解して)同意したとなる。
http://msdn.microsoft.com/en-us/library/ms632615(VS.85).aspx
> WM_CANCELMODE
> the system sends this message to the active window when a dialog box or
> message box is displayed.
フォーカス消失関連処理中に MessageBox を出すのは良い類の行動では無い様子。
http://msdn.microsoft.com/en-us/library/ms646282(VS.85).aspx
> WM_KILLFOCUS
> While processing this message, do not make any function calls that display
> or activate a window.