WindowsXP VC++.NET 2003 で開発しております。
テンプレートを使わずにコントロールを2つ、直接作成したのですが、
2つのコントロール間のTabキーによるフォーカス移動ができません。
親ウインドウで、CreateWindowExにWS_EX_CONTROLPARENTを指定して、
各コントロールにWS_TABSTOPをしてみたのですが、どうもうまくいきません。
各コントロールはそれぞれ、テキストボックス、ボタンです。
このテキストボックスでTABキーを押した場合、インデントされるだけで、
ボタンにフォーカスが移動するようなことはありません。
そもそも、ボタンから、テキストボックスにTABキーでフォーカス移動することもできま
せん。
以下にソースの1部を書きます。
--------WinProc内--------
.
..
...
case WM_CREATE:
/* テキスト入力ボックスを作成 */
hTextbox=CreateWindowEx(0, EDIT,",
WS_CHILD | ES_MULTILINE | WS_VSCROLL
|WS_GROUP|WS_TABSTOP,
0, 0, 0, 0,
hWnd,
(HMENU)2,
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
ShowWindow(hTextbox,SW_SHOW);
/* 送る ボタンを作成 */
hButton=CreateWindowEx(0, BUTTON,送る,
WS_CHILD|WS_GROUP|WS_TABSTOP ,
0, 0,128, 32,
hWnd,
(HMENU)ID_BTN,
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
ShowWindow(hButton,SW_SHOW);
break;
.
..
...
case WM_SIZE:
MoveWindow(hButton, LOWORD(lPa)-70,
HIWORD(lPa)-36,64, 32, TRUE);
MoveWindow(hTextbox, 5, HIWORD(lPa)*0.77+10,
LOWORD(lPa)-80, HIWORD(lPa)-HIWORD(lPa)*0.77-
15, TRUE);
break;
.
..
...
--------WinMain内--------
.
..
...
hWnd = CreateWindowEx(
WS_EX_CONTROLPARENT,
szWinName,
szWinTitle,
WS_OVERLAPPEDWINDOW,
0,
0,
SCREEN_WIDTH,
SCREEN_HEIGHT,
NULL,
NULL,
hInst,
NULL
);
アドバイスよろしくお願いいたします。
メッセージループで IsDialogMessage() を呼んでいますか?
dairygoods様、お早い返事ありがとうございます。
恥ずかしながら、IsDialogMessage()なるものを知りませんでした。
ソースを下記のように書き換えました。
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
↑この部分を、↓このように書き換えました。
while(GetMessage(&msg,NULL,0,0))
{
if(!IsDialogMessage(hWnd,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
しかし、残念ながらTABキーでのフォーカス移動はできませんでした。
改善されたことは1つあります。
テキストボックス内でTABキーを入力した場合、
インデントされなくなりました。
> hWnd = CreateWindowEx(
> WS_EX_CONTROLPARENT,
このスタイルは、作ったダイアログを親ダイアログの中に埋め込み、
ダイアログとしての処理は親に任せる時に使うものなので、
不要のような気がします。
あと、今回の問題とは関係ないですが、
コントロールを作ってからいちいちShowWindowしなくても、
WS_VISIBLE スタイルというものがあります。
dairygoods様
おっしゃるとおり、ShowWindowしなくても、WS_VISIBLEで表示できました。
ただ、相変わらずTABでフォーカス移動ができません・・・。
指摘されたとおり、親ウインドウのWS_EX_CONTROLPARENTの記述を削除しましたが、
どうしてもフォーカス移動できません。
何かいい方法はないでしょうか。。。
DefDlgProc
http://www.microsoft.com/japan/msdn/library/ja/jpwinui/html/_win32_defdlgproc.asp
ここの「解説」にある、カスタムダイアログボックスに関する要件は
満たしていますでしょうか?
dairygoods様
すみません。私が初心者なもので、
dairygoods様がおっしゃっている意味がわかりません。
私は、DefWindowProcをウインドウプロシージャの最後に記述しています。
ここを、DefDlgProcに書き換えたところ、ウインドウが表示されなくなりました。
もうちょっと詳しいソースを記述します。
//-----WinMain----------
INT APIENTRY WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR pCmdLine, INT
nCmdShow )
{
.
...
....
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = NULL;
wc.lpfnWndProc = WinProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szWinName;
wc.hIconSm = NULL;
if (!RegisterClassEx(&wc)) return (FALSE);
hWnd = CreateWindowEx(0,
szWinName,
szWinTitle,
WS_OVERLAPPEDWINDOW|WS_SYSMENU,
0,
0,
SCREEN_WIDTH,
SCREEN_HEIGHT,
NULL,
NULL,
hInst,
NULL
);
ShowWindow(hWnd, nWinMode);
UpdateWindow(hWnd);
.
...
....
while(GetMessage(&msg,NULL,0,0))
{
if(!IsDialogMessage(hWnd,&msg))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
.
...
....
//-----ウインドウプロシージャ-------
LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wPa, LPARAM lPa)
{
.
...
....
case WM_CREATE:
/* テキスト入力ボックスを作成 */
hTextbox=CreateWindowEx(0, EDIT,",
WS_CHILD | ES_MULTILINE | WS_VSCROLL
|WS_GROUP|WS_TABSTOP|WS_VISIBLE,
0, 0, 0, 0,
hWnd,
(HMENU)2,
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
/* 送る ボタンを作成 */
hButton=CreateWindowEx(0, BUTTON,送る,
WS_CHILD|WS_GROUP|WS_TABSTOP|WS_VISIBLE,
0, 0,128, 32,
hWnd,
(HMENU)ID_BTN,
(HINSTANCE)GetWindowLong(hWnd, GWL_HINSTANCE), NULL);
break;
.
..
...
case WM_SIZE:
MoveWindow(hButton, LOWORD(lPa)-70,
HIWORD(lPa)-36,64, 32, TRUE);
MoveWindow(hTextbox, 5, HIWORD(lPa)*0.77+10,
LOWORD(lPa)-80, HIWORD(lPa)-HIWORD(lPa)*0.77-
15, TRUE);
break;
.
..
...
default:
return DefWindowProc(hWnd, msg, wPa, lPa);
.
..
...
---------------
以上です。
もうひとつ、
> どのような場合でも、カスタムダイアログボックスクラスでは、
> WNDCLASS の cbWndExtra メンバは少なくとも DLGWINDOWEXTRA
> の値に設定しなければなりません。
という記載がありますね。
ところで、ダイアログリソースを使って CreateDialog した方が
わざわざダイアログとしての基本動作の部分について思い悩む
必要もないと思うのですが、なにか動的にコントロールを生成
しなければならない理由がおありでしょうか。
なんか食い違ってんね。
>> dairygoods さん
作ってるのは、ダイアログボックスじゃないようですよ。
ん。
標準のダイアログクラスを使わないで、独自ウィンドウクラスを使うなら
「カスタムダイアログ」にしなきゃだめ、てことじゃないかと。
http://msdn.microsoft.com/library/default.asp?url=/library/en-
us/winui/winui/windowsuserinterface/windowing/windows/windowreference/windowfun
ctions/createwindowex.asp
の最後のほうに記述がありますね。
DefWindowProc のかわりに DefDlgProc を呼び出すようにウィンドウプロシージャを
変更する必要があるみたい。
でも、dairygoods さんが言われているようにダイアログを使うのが一般的なのかも。
メインウィンドウに子ダイアログを貼り付けて、その中にコントロールを配置する。
MFC のフォームビューなんかはそのパターンですよね。
(背景色なんかは簡単に変えられると思います)
> 作ってるのは、ダイアログボックスじゃないようですよ。
WS_TABSTOP スタイルのコントロールをTABで移動する機能は、
DefDlgProc や IsDialogMessage の組合せで実現されており、
これらを利用するウィンドウは、本人にそのつもりが無くても
(モードレス)ダイアログボックスです。
Windows のダイアログボックス機能に頼らず、
WndProcに自力でTAB遷移を組み込むという方法もありますが。
リンク先訂正です。(^^;
> http://msdn.microsoft.com/library/default.asp?url=/library/en-
>us/winui/winui/windowsuserinterface/windowing/windows/windowreference/windowfu
n
>ctions/createwindowex.asp
http://msdn.microsoft.com/library/en-
us/winui/winui/windowsuserinterface/windowing/dialogboxes/usingdialogboxes.asp?
frame=true
(改行はつなげてください)
dairygoods様 R2様 シャノン様
おっしゃるとおりに、DLGWINDOWEXTRAを記述したところ、
フォーカス移動ができるようになりました!
カスタムダイアログ、ウインドウ、ダイアログなどの違いがいまいちわからず、
すこし混乱していますが、とりあえずは解決できてうれいしです。
リソースを使わず、あえて直接書いたのは、
単にリソースの使い方がよくわからないというだけです。
フォーカス移動はできたのですが、今度は作成したウインドウの背景色が
ダイアログボックス特有のグレーになってしまいました。
ですが、ウインドウプロシージャ(の、つもりだったんですが、もうダイアログプロシー
ジャなのかな・・・。)の中を、下記のように書き換えたところ、もとのブラック色にもど
すことができました。
case WM_CTLCOLORDLG:
return (long)GetStockObject(BLACK_BRUSH);
みなさま、どうもありがとうございました。
> dairygoods さん、R2 さん
ぬう、そんな秘密があったとは。
役立たずで申し訳ありませんでした。