環境:MFC、VS2012、Win7
Enterキーを無効として、スペースだけ有効なボタンを
ダイアログに張り付けています。
リソースから全てのデフォルトボタンは無効としているのですが、
ボタンをクリックすると青枠表示となってしまい
デフォルトボタンのように表示されてしまいます。
Enterキーは無効としているため、クリックしても青枠が表示されないように
したいのですが、どのようにすれば良いでしょうか?
WindowsOSが提供するコントロールをまんま使用している限りできません。
従って、
1.キーボードフォーカス、
2.デフォルト設定
3.マウスホバー
等に、一切反応しないようにボタンをサブクラス化するか、
カスタムドローで済んでしまうかもしれません。
確実に行うには、ボタン自体を自作するのがよいでしょう。
ただし、
WindowsOSに対して詳細な知識をもっていれば、それほど手間はかかりませんが、、
そうでない場合は、労多くして・・ということになるでしょう。
一般に、Windowの標準動作と異なる動作をさせることは、
ユーザーにとって迷惑で煩わしい出来事にすぎません。
必須の機能でない限り、もっと重要な部分に注力した方がよいかもしれません。
回答ありがとうございます。
サブクラス化はしているのですが、
どのような時にデフォルトボタンになるイベントが来ている
のかわかりません。
ボタンクリックイベント時に、強制的に
デフォルト無効としても駄目でした。
仲澤@失業者さんの提案内容が難しければ、ビットマップボタンにしてボタンのイメージ
を自分で描くのも良いかもしれません。
ボタンの数が多い場合は、CBitmapButtonから派生して自前で描画することになります
が、結構サンプルも出回ってますし難易度は高くないと思います。
手頃な紹介サイトがあったので参考までにどうぞ。
http://www7b.biglobe.ne.jp/~makandat/VC/Group6/OwnerDraw.htm
オーナードローと言うことでしょうか?
オーナードローにすると、ビジュアルスタイルがクラシック
になってしまい、
今までと見た目が変わってしまうため避けたいです。
(オーナードローでWin7のようなビジュアルスタイル適用法
がわかりませんでした)
SetFocusイベントを受け取ったタイミングで
無理やりデフォルトボタンフラグを削除することである程度
の希望通りの動作は出来ましたが、
TABキーで移動してくると、やはり青枠が付いてしまいま
す。
Win7の標準ボタンの見た目のまま、青枠だけを表示しないよ
うにしたいのですが、
やはり難しいのでしょうか、
フォーカス枠のことを言ってるんでしょうか。
でしたら…
http://www.ipentec.com/document/document.aspx?page=csharp-create-no-focused-butt
on
まず、デフォルトボタンに設定されるときに通知は来ないと思います。
次にボタンのサブクラス化ができているならば、
デフォルト状態を解除するのは GetWindowLongPtr(GWL_STYLE);で、
取得したフラグ状態の BS_DEFPUSHBUTTON フラグを解除し、
SetWindowLongPtr()すればできるのですが、
多分WM_PAINT 時に常に設定しなおす必要があると予測できます。
キーボードフォーカスはWS_TABSTOPを外すだけではだめで、
マウスのボタンダウン、アップの時に誰かに逃がさなくてはなりません。
親がDLGであると、子のどれかにフォーカスを設定しにくるので、
難しい面があります。
親をDLGではなく、通常のウインドウにすれば、この辺りは逃れられます。
ただし、親をDLGでなくしても、
1.ボタン上でマウス左Down
2.そのままボタン外にドラッグアウト
等をすると、押下状態(表示色)が保持されてしまいます。
この解除方法は調べたことがありません。
名称は忘れましたが、ボタン名称の周りを囲む点線も表示されます。
残念ながら、この解除方法も調べたことがありません。
といった具合で、これらをすべてやるくらいなら、
作っちまった方が楽かもしれないというわけなのです(vv;)。
さて、ところで、どうしてこのようなことをやろうとしているのでしょうか。
そっちの方を説明すると、別の解決方法もあるかもしれません。
懸念しているのはマインスイーパー盤面にならんだボタンのような
動作をさせようとしているのであれば「あれはボタンではない」
ということをSpy++でご確認ください(笑)。
WM_PAINTイベント時にデフォルトボタンオフで出来ました。
自分でもWM_PAINTかな・・・と行きついたところでしたが、
ほんとにここで良いか不明でしたので、回答を得られて確証持てました。
ありがとうございます。
どうしてこんなことを・・・と言いますと
ダイアログのEnterキー操作を無効にしており、
デフォルトボタンの意味が全くありませんでした。
にも関わらず、青枠が表示されているのはおかしい、
ということで非表示にしたかったのです。
ちなみに、ご提示頂いた方法の
LONG_PTR lp = GetWindowLongPtr(this->m_hWnd, GWL_STYLE);
if ( lp & BS_DEFPUSHBUTTON ) {
SetButtonStyle(BS_PUSHBUTTON);
}
だとラジオボタンの場合におかしな事になってしまったので、
if ( GetButtonStyle() == BS_DEFPUSHBUTTON ) {
SetButtonStyle(BS_PUSHBUTTON);
}
と実装しました。
BS_DEFPUSHBUTTONってビット演算でIFできないんでしょうか?
// BS_DEFPUSHBUTTONを「落とす」コードは
DWORD Flag = ( DWORD)::GetWindowLongPtr( hWndBtton, GWL_STYLE);
Flag &=( ~BS_DEFPUSHBUTTON); // ビット反転したものとのANDをとる
::SetWindowLongPtr( hWndBtton, GWL_STYLE, LONG( Flag));
ですね。ビット演算は慣れてないとわかりづらいですね。
WinUser.h を見ると、以下のように並んでるので
そのやり方ですと BS_AUTOCHECKBOX 等が入ってきた場合も
落ちてしまうんですよね・・・
#define BS_PUSHBUTTON 0x00000000L
#define BS_DEFPUSHBUTTON 0x00000001L
#define BS_CHECKBOX 0x00000002L
#define BS_AUTOCHECKBOX 0x00000003L
#define BS_RADIOBUTTON 0x00000004L
....
0,1,2,4,8...と並んでいるのならビット演算で落とせそうなのですが
この並びの場合、BS_DEFPUSHBUTTON だけ「落とす」方法がわかりませんでした。
なるほど、4bitが一括してフラグ化されてますね。失礼しました。
BS_TYPEMASKでマスクしてBS_DEFPUSHBUTTONならBS_PUSHBUTTON
に変更で良いのではないでしょうか。
DWORD BsStyle4bit = Flag & BS_TYPEMASK;
if( BsStyle4bit == BS_DEFPUSHBUTTON){
BsStyle4bit = BS_PUSHBUTTON;
}
Flag &=(~BS_TYPEMASK);// 4bit落とす
Flag |= BsStyle4bit;// まぁ0ですけどね
なるほど、BS_TYPEMASKはマスク用に用意されてるんですね。
やはり下位WORDを抜きだして見るしかないんですね・・・
なんでこんな並びのフラグにしたんだMicrosoft。
勉強になりました。
最後までご回答いただきありがとうございました!
本来の問題とは関係ありませんが…。
>なんでこんな並びのフラグにしたんだMicrosoft。
複数の状態が被ることがないから…かと。
自動チェックボックスで、プッシュボタン。というスタイルはないですし。
# PUSHBUTTONでDEFPUSHBUTTONは被るような気もしますが…そこんところはどうなんだろう??