dポイントプレゼントキャンペーン実施中!

ダイアログボックスのボタンコントロールのフォーカスについて
教えて下さい。

 モーダルダイアログにボタン「OK」を一つ貼り付けて
それを「標準のボタン」(BS_DEFPUSHBUTTON)として作成したのですが
ダイアログ表示直後は下画像(1)のようになってエンターキーを押しても
反応しません。何度かカーソルキーを押すとようやく(2)のように
ボタンに枠線がついてエンターで押せるようになるのですが
ダイアログ表示直後に(2)のようにするにはどうするべきでしょうか?


ダイアログのコールバック・プロシージャ(WM_INITDIALOG部分でボタン作成)

LRESULT CALLBACK SettingWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp){

switch (msg){
case WM_INITDIALOG:
CreateWindowEx(0x00000000,"BUTTON","OK",
WS_CHILD |WS_VISIBLE| WS_TABSTOP | BS_DEFPUSHBUTTON,
16,16,80,21,hWnd,(HMENU)IDOK,GetModuleHandle(0),0);
return TRUE;
}
return FALSE;
}

「ダイアログボックスのボタンコントロールの」の質問画像

A 回答 (4件)

>但し付けていただいたリンク先の説明によるとTRUEを返す場合、


>「最初の WS_TABSTOP をもつコントロールにフォーカスがセットされます。」
>ということから考えれば、TRUE戻しでもこのボタンにフォーカスが当たっても良い筈です。
>この場合何故そうならないのかはまだ分かりません。

WM_INITDIALOGのWPARAMに「フォーカスが当たる予定のコントロールID」が入って呼ばれますが、
WM_INITDIALOGをOSが発行した時点ではWM_INITDIALOGのハンドラ内で生成されるコントロールは「まだ生成されていない」ですし、付与されるコントロールIDも不明です。

となると、WM_INITDIALOGのハンドラ内で生成したコントロールにWS_TABSTOPが付いていてもその時点ではどうしようもありません。

BS_DEFPUSHBUTTONが効くのも、WM_INITDIALOGが発行される前、OS側がWM_INITDIALOGのWPARAMに設定するコントロールIDを決定するために精査するとき…と言うことなのではないでしょうか。

この回答への補足

お礼の文面の訂正を。
>>WM_INITDIALOG内でコントロールを作るなということですね。
WM_INITDIALOG内でコントロールを作るなというより
もしそこで作った場合は自分でフォーカスを合わせる、ということだと思います。

それから
>> またBS_PUSHBUTTONにした上で「フォーカス当てのFALSE戻し」にした時は
この場合は逆にフォーカスが当たらないままでした。
これは「フォーカスが当たらない」のではなくて、図(1)の状態になる(ボタンに実線枠が
付かずエンター押しが効かない)の間違いでした。
「点線」のフォーカスそのものは当たっているものと思います。

以上を訂正させて頂きます。申し訳ありません。

補足日時:2010/04/22 23:35
    • good
    • 0
この回答へのお礼

なるほど。確かに説明されている通りです。
解説を貰ってストンと自分でもようやく理解出来ました。
>>WM_INITDIALOGをOSが発行した時点ではWM_INITDIALOGのハンドラ内で生成されるコントロールは「まだ生成されていない」ですし、付与されるコントロールIDも不明です。
まさにそれが原因で起こっていた現象だと思います。
WM_INITDIALOG内でコントロールを作るなということですね。
リソースエディタで作成すれば大丈夫なんでしょうか?

有難うございます。またよろしくお願いします。

お礼日時:2010/04/22 23:16

ダイアログボックスのクライアント内(何かのコントロール)にフォーカスが設定されていれば、


EnterキーでIDOK、ESCキーでIDCANCELが飛んでくるかと思われますが…。
ということで、作成するボタンのIDは別にしないと、デフォルト動作でIDOKが飛んでいるのかどうか判らなくなると思われます。

ダイアログボックスの最初のフォーカスはシステム側で設定されてきます。
# WM_INITDIALOGのWPARAMにコントロールIDが設定されています。
WM_INITDIALOGのメッセージ処理中に、最初のフォーカスを変更したい場合は、#1さんの掲示されているSetFocus()を使用し、
WM_INITDIALOGの応答としてFALSEを返却する必要があります。
http://wisdom.sakura.ne.jp/system/winapi/win32/w …

ダイアログプロシージャからの返却の場合、SetWindowLong()でDWL_MSGRESULTに設定して返すことになりますが…
WM_INITDIALOGの場合はそのまま返却でよい…みたいです。
http://msdn.microsoft.com/en-us/library/ms645428 …

この回答への補足

ここまでのテスト結果を。

IDをIDOKにしてはいけないという所はまだ理解が追いついてないのですが
とりあえずIDを「CommandButton1」などに替えてみてテストしてみました。
ただその時点ではまだ現象は変わりませんでした。
 次にその設定のまま「SetFocusでフォーカスをボタンに当ててFALSE戻し」
にすると、これは上手くフォーカスが当たりエンター押しも効きました。
但し付けていただいたリンク先の説明によるとTRUEを返す場合、
「最初の WS_TABSTOP をもつコントロールにフォーカスがセットされます。」
ということから考えれば、TRUE戻しでもこのボタンにフォーカスが当たっても良い筈です。
この場合何故そうならないのかはまだ分かりません。
最後にBS_DEFPUSHBUTTONを「BS_PUSHBUTTON」に替えてやってみたのですが
これはTRUE戻しでも上手く行きました。だとするとDEFPUSHBUTTONは使えないの
かな、とも思ってしまうのですが、、、
 またBS_PUSHBUTTONにした上で「フォーカス当てのFALSE戻し」にした時は
この場合は逆にフォーカスが当たらないままでした。
ちょっと迷いそうになってますが、もう少しテストを続けてみます。

補足日時:2010/04/22 22:20
    • good
    • 0
この回答へのお礼

有難うございます。書いて頂いたコード、リンクを参考にさせてもらいながら
これからこちらでもテストしたいと思います。少し時間を貰って、また報告します。

お礼日時:2010/04/22 16:43

XP で試してみたところ、なぜかよくわかりませんが、BS_DEFPUSHBUTTON ではなく BS_PUSHBUTTON にするとダイアログ表示直後でも ENTER キーで反応しました。

ただし、概観はやはり BS_DEFPUSHBUTTON ではなく BS_PUSHBUTTON のものです。

この回答への補足

ここまでのテスト結果を。

IDをIDOKにしてはいけないという所はまだ理解が追いついてないのですが
とりあえずIDを「CommandButton1」などに替えてみてテストしてみました。
ただその時点ではまだ現象は変わりませんでした。
 次にその設定のまま「SetFocusでフォーカスをボタンに当ててFALSE戻し」
にすると、これは上手くフォーカスが当たりエンター押しも効きました。
但し付けていただいたリンク先の説明によるとTRUEを返す場合、
「最初の WS_TABSTOP をもつコントロールにフォーカスがセットされます。」
ということから考えれば、TRUE戻しでもこのボタンにフォーカスが当たっても良い筈です。
この場合何故そうならないのかはまだ分かりません。
最後にBS_DEFPUSHBUTTONを「BS_PUSHBUTTON」に替えてやってみたのですが
これはTRUE戻しでも上手く行きました。だとするとDEFPUSHBUTTONは使えないの
かな、とも思ってしまうのですが、、、
 またBS_PUSHBUTTONにした上で「フォーカス当てのFALSE戻し」にした時は
この場合は逆にフォーカスが当たらないままでした。
ちょっと迷いそうになってますが、もう少しテストを続けてみます。

補足日時:2010/04/22 22:20
    • good
    • 0
この回答へのお礼

有難うございます。書いて頂いたコード、リンクを参考にさせてもらいながら
これからこちらでもテストしたいと思います。少し時間を貰って、また報告します。

お礼日時:2010/04/22 16:43

 こんばんは。



 う~む、ボタンハンドルを指定してSetFocus()APIを呼び出しても無理でしょうか。
 試して見ましたが、SetFocus()APIなしでも、特に問題なく反応しています。

// test.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
#include"stdafx.h"
#include<windows.h>
#include"resource.h"
//ダイアログ
INT CALLBACK SettingWndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
switch (msg)
{
case WM_INITDIALOG:
{
HWND hButton = ::CreateWindowEx(0, TEXT("BUTTON"), TEXT("OK"),
WS_CHILD |WS_VISIBLE | WS_TABSTOP | BS_DEFPUSHBUTTON,
16, 16, 80, 21, hWnd, (HMENU)IDOK, ::GetModuleHandle(NULL), 0);

//取りあえず呼んでみる
::SetFocus(hButton);
return TRUE;
}

case WM_COMMAND:
if(wp == IDOK)
{
::EndDialog(hWnd, FALSE);
}
break;
}
return FALSE;
}
//ウィンドウ
LRESULT CALLBACK WindowProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
//左ボタンクリックでダイアログを出す
case WM_LBUTTONDOWN:
::DialogBox(::GetModuleHandle(NULL), MAKEINTRESOURCE(IDD_DIALOG1), hWnd, &::SettingWndProc);
return 0;

case WM_NCDESTROY:
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

 文字数制限により、WinMain()を省略。

この回答への補足

ここまでのテスト結果を。

IDをIDOKにしてはいけないという所はまだ理解が追いついてないのですが
とりあえずIDを「CommandButton1」などに替えてみてテストしてみました。
ただその時点ではまだ現象は変わりませんでした。
 次にその設定のまま「SetFocusでフォーカスをボタンに当ててFALSE戻し」
にすると、これは上手くフォーカスが当たりエンター押しも効きました。
但し付けていただいたリンク先の説明によるとTRUEを返す場合、
「最初の WS_TABSTOP をもつコントロールにフォーカスがセットされます。」
ということから考えれば、TRUE戻しでもこのボタンにフォーカスが当たっても良い筈です。
この場合何故そうならないのかはまだ分かりません。
最後にBS_DEFPUSHBUTTONを「BS_PUSHBUTTON」に替えてやってみたのですが
これはTRUE戻しでも上手く行きました。だとするとDEFPUSHBUTTONは使えないの
かな、とも思ってしまうのですが、、、
 またBS_PUSHBUTTONにした上で「フォーカス当てのFALSE戻し」にした時は
この場合は逆にフォーカスが当たらないままでした。
ちょっと迷いそうになってますが、もう少しテストを続けてみます。

補足日時:2010/04/22 22:21
    • good
    • 0
この回答へのお礼

有難うございます。書いて頂いたコード、リンクを参考にさせてもらいながら
これからこちらでもテストしたいと思います。少し時間を貰って、また報告します。

お礼日時:2010/04/22 16:44

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!

このQ&Aを見た人はこんなQ&Aも見ています


このQ&Aを見た人がよく見るQ&A