デフォルトボタン表示を無効にしたい

[戻る]
2016/02/09(火) 00:45:41
環境:MFC、VS2012、Win7

Enterキーを無効として、スペースだけ有効なボタンを
ダイアログに張り付けています。

リソースから全てのデフォルトボタンは無効としているのですが、
ボタンをクリックすると青枠表示となってしまい
デフォルトボタンのように表示されてしまいます。

Enterキーは無効としているため、クリックしても青枠が表示されないように
したいのですが、どのようにすれば良いでしょうか?

仲澤@失業者 2016/02/09(火) 10:29:18
WindowsOSが提供するコントロールをまんま使用している限りできません。
従って、
 1.キーボードフォーカス、
 2.デフォルト設定
 3.マウスホバー
等に、一切反応しないようにボタンをサブクラス化するか、
カスタムドローで済んでしまうかもしれません。
確実に行うには、ボタン自体を自作するのがよいでしょう。

ただし、
WindowsOSに対して詳細な知識をもっていれば、それほど手間はかかりませんが、、
そうでない場合は、労多くして・・ということになるでしょう。
一般に、Windowの標準動作と異なる動作をさせることは、
ユーザーにとって迷惑で煩わしい出来事にすぎません。
必須の機能でない限り、もっと重要な部分に注力した方がよいかもしれません。

2016/02/09(火) 11:15:44
回答ありがとうございます。

サブクラス化はしているのですが、
どのような時にデフォルトボタンになるイベントが来ている
のかわかりません。

ボタンクリックイベント時に、強制的に
デフォルト無効としても駄目でした。

AR 2016/02/09(火) 13:22:20
仲澤@失業者さんの提案内容が難しければ、ビットマップボタンにしてボタンのイメージ
を自分で描くのも良いかもしれません。
ボタンの数が多い場合は、CBitmapButtonから派生して自前で描画することになります
が、結構サンプルも出回ってますし難易度は高くないと思います。

手頃な紹介サイトがあったので参考までにどうぞ。
http://www7b.biglobe.ne.jp/~makandat/VC/Group6/OwnerDraw.htm

2016/02/09(火) 16:43:21
オーナードローと言うことでしょうか?
オーナードローにすると、ビジュアルスタイルがクラシック
になってしまい、
今までと見た目が変わってしまうため避けたいです。
(オーナードローでWin7のようなビジュアルスタイル適用法
がわかりませんでした)

SetFocusイベントを受け取ったタイミングで
無理やりデフォルトボタンフラグを削除することである程度
の希望通りの動作は出来ましたが、
TABキーで移動してくると、やはり青枠が付いてしまいま
す。

Win7の標準ボタンの見た目のまま、青枠だけを表示しないよ
うにしたいのですが、
やはり難しいのでしょうか、

みい 2016/02/09(火) 18:19:55
フォーカス枠のことを言ってるんでしょうか。
でしたら…

http://www.ipentec.com/document/document.aspx?page=csharp-create-no-focused-butt
on

仲澤@失業者 2016/02/09(火) 19:17:32
まず、デフォルトボタンに設定されるときに通知は来ないと思います。

次にボタンのサブクラス化ができているならば、
デフォルト状態を解除するのは GetWindowLongPtr(GWL_STYLE);で、
取得したフラグ状態の BS_DEFPUSHBUTTON フラグを解除し、
SetWindowLongPtr()すればできるのですが、

多分WM_PAINT 時に常に設定しなおす必要があると予測できます。

キーボードフォーカスはWS_TABSTOPを外すだけではだめで、
マウスのボタンダウン、アップの時に誰かに逃がさなくてはなりません。
親がDLGであると、子のどれかにフォーカスを設定しにくるので、
難しい面があります。
親をDLGではなく、通常のウインドウにすれば、この辺りは逃れられます。

ただし、親をDLGでなくしても、

 1.ボタン上でマウス左Down
 2.そのままボタン外にドラッグアウト

等をすると、押下状態(表示色)が保持されてしまいます。
この解除方法は調べたことがありません。

名称は忘れましたが、ボタン名称の周りを囲む点線も表示されます。
残念ながら、この解除方法も調べたことがありません。

といった具合で、これらをすべてやるくらいなら、
作っちまった方が楽かもしれないというわけなのです(vv;)。

さて、ところで、どうしてこのようなことをやろうとしているのでしょうか。
そっちの方を説明すると、別の解決方法もあるかもしれません。
懸念しているのはマインスイーパー盤面にならんだボタンのような
動作をさせようとしているのであれば「あれはボタンではない」
ということをSpy++でご確認ください(笑)。

2016/02/09(火) 23:30:23
[[解決]]
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できないんでしょうか?

仲澤@失業者 2016/02/10(水) 10:14:24
// BS_DEFPUSHBUTTONを「落とす」コードは
DWORD    Flag    = ( DWORD)::GetWindowLongPtr( hWndBtton, GWL_STYLE);
Flag    &=( ~BS_DEFPUSHBUTTON);  // ビット反転したものとのANDをとる
::SetWindowLongPtr( hWndBtton, GWL_STYLE, LONG( Flag));
ですね。ビット演算は慣れてないとわかりづらいですね。

2016/02/12(金) 04:45:50
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 だけ「落とす」方法がわかりませんでした。

仲澤@失業者 2016/02/12(金) 11:59:27
なるほど、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ですけどね

2016/02/15(月) 23:17:47
なるほど、BS_TYPEMASKはマスク用に用意されてるんですね。

やはり下位WORDを抜きだして見るしかないんですね・・・
なんでこんな並びのフラグにしたんだMicrosoft。

勉強になりました。
最後までご回答いただきありがとうございました!

瀬戸っぷ [E-Mail] 2016/02/16(火) 10:45:28
本来の問題とは関係ありませんが…。

>なんでこんな並びのフラグにしたんだMicrosoft。

複数の状態が被ることがないから…かと。
自動チェックボックスで、プッシュボタン。というスタイルはないですし。
# PUSHBUTTONでDEFPUSHBUTTONは被るような気もしますが…そこんところはどうなんだろう??

古いスレッドには追加発言できません。