ネットの間違いとかを指摘するつもりが一昨日変な挙動を見つけたのでそれを書くことにする。
発見時はVS2010/Win7だったが再現はVS2013/Win7で行った。
再現手順
- VS2013でダイアログベースアプリケーション作成
- ラジオボタンを配置
- ラジオボタンプロパティのAutoをFalseにする
- ラジオボタンにBN_CLICKEDイベントを登録する
BEGIN_MESSAGE_MAP(CMFCApplication2Dlg, CDialogEx)
ON_BN_CLICKED(IDC_RADIO1, &CMFCApplication2Dlg::OnBnClickedRadio1)
END_MESSAGE_MAP()
- クリックイベントでメッセージボックスを表示する
void CMFCApplication2Dlg::OnBnClickedRadio1()
{
AfxMessageBox(_T("radio button clicked"));
}
発生現象
実行してそのラジオボタンをクリックするとダイアログが表示される。
そしてメッセージのOKを押すとまたダイアログが表示される。5~10回程度出てくる。
また、マウスオーバーでクリックイベントが起きることがある。
原因
Windowsの仕様と言う名のバグ。
ラジオボタンはSETFOCUSされるとBN_CLICKEDが発行されるらしい。
MessageBoxはご丁寧に前のコントロールにSETFOCUSしてくるようなので、BN_CLICKEDが発行され、またMessageBoxが表示される。
ラジオボタンがBST_UNCHECKEDの状態でのみ起きる。
マウスオーバーでBN_CLICKEDが出るのもフォーカス移動を検知している可能性が高い。
対策
AUTORADIOBUTTONにするか、諦めるか、メッセージボックスを出さないようにする。
ラジオボタンがクリックされたとき、それを無かったことにしたいだけなのに
メッセージボックスを出すと問題が起きて制御不能である。
ラジオボタンがチェックされていると発生しないので、FOCUSされたら確実にチェックされるという前提で全ての処理を組んでいるらしい。
BN_CLICKEDを処理させる事はキャンセルもありえるのだが、MSはそれを考慮しておらず、仕様に不具合を抱えている。
ラジオボタンでBN_CLICKEDが使用不可能ならそう書いて置けばいいのに。
参考
Button Messages(MSDN)
Draws a focus rectangle on the button getting the focus. For radio buttons and automatic radio buttons, the parent window is sent a BN_CLICKED notification code.
まとめ
.netにしよう。