直接作成したコントロールのTABフォーカス移動について

[戻る]
ねこ 2005/06/25(土) 10:54:14
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
       );


アドバイスよろしくお願いいたします。

dairygoods 2005/06/25(土) 11:10:10
メッセージループで IsDialogMessage() を呼んでいますか?

ねこ 2005/06/25(土) 13:12:40
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キーを入力した場合、
インデントされなくなりました。

dairygoods 2005/06/25(土) 20:06:40
>    hWnd = CreateWindowEx(
>        WS_EX_CONTROLPARENT,

このスタイルは、作ったダイアログを親ダイアログの中に埋め込み、
ダイアログとしての処理は親に任せる時に使うものなので、
不要のような気がします。

あと、今回の問題とは関係ないですが、
コントロールを作ってからいちいちShowWindowしなくても、
WS_VISIBLE スタイルというものがあります。

ねこ 2005/06/25(土) 20:45:21
dairygoods様

おっしゃるとおり、ShowWindowしなくても、WS_VISIBLEで表示できました。

ただ、相変わらずTABでフォーカス移動ができません・・・。
指摘されたとおり、親ウインドウのWS_EX_CONTROLPARENTの記述を削除しましたが、
どうしてもフォーカス移動できません。

何かいい方法はないでしょうか。。。

dairygoods 2005/06/25(土) 21:27:50
DefDlgProc
http://www.microsoft.com/japan/msdn/library/ja/jpwinui/html/_win32_defdlgproc.asp

ここの「解説」にある、カスタムダイアログボックスに関する要件は
満たしていますでしょうか?

ねこ 2005/06/25(土) 22:21:22
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);

.
..
...
---------------

以上です。

dairygoods 2005/06/25(土) 22:36:36
もうひとつ、
> どのような場合でも、カスタムダイアログボックスクラスでは、
> WNDCLASS の cbWndExtra メンバは少なくとも DLGWINDOWEXTRA 
> の値に設定しなければなりません。
という記載がありますね。

ところで、ダイアログリソースを使って CreateDialog した方が
わざわざダイアログとしての基本動作の部分について思い悩む
必要もないと思うのですが、なにか動的にコントロールを生成
しなければならない理由がおありでしょうか。

シャノン 2005/06/25(土) 23:31:17
なんか食い違ってんね。

>> dairygoods さん

作ってるのは、ダイアログボックスじゃないようですよ。

R2 2005/06/26(日) 00:22:38
ん。

標準のダイアログクラスを使わないで、独自ウィンドウクラスを使うなら
「カスタムダイアログ」にしなきゃだめ、てことじゃないかと。

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 のフォームビューなんかはそのパターンですよね。
(背景色なんかは簡単に変えられると思います)

dairygoods 2005/06/26(日) 00:40:37
> 作ってるのは、ダイアログボックスじゃないようですよ。

WS_TABSTOP スタイルのコントロールをTABで移動する機能は、
DefDlgProc や IsDialogMessage の組合せで実現されており、
これらを利用するウィンドウは、本人にそのつもりが無くても
(モードレス)ダイアログボックスです。

Windows のダイアログボックス機能に頼らず、
WndProcに自力でTAB遷移を組み込むという方法もありますが。

R2 2005/06/26(日) 01:15:56
リンク先訂正です。(^^;

>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
(改行はつなげてください)

ねこ 2005/06/26(日) 12:08:31
[[解決]]
dairygoods様 R2様 シャノン様

おっしゃるとおりに、DLGWINDOWEXTRAを記述したところ、
フォーカス移動ができるようになりました!
カスタムダイアログ、ウインドウ、ダイアログなどの違いがいまいちわからず、
すこし混乱していますが、とりあえずは解決できてうれいしです。
リソースを使わず、あえて直接書いたのは、
単にリソースの使い方がよくわからないというだけです。

フォーカス移動はできたのですが、今度は作成したウインドウの背景色が
ダイアログボックス特有のグレーになってしまいました。
ですが、ウインドウプロシージャ(の、つもりだったんですが、もうダイアログプロシー
ジャなのかな・・・。)の中を、下記のように書き換えたところ、もとのブラック色にもど
すことができました。

case WM_CTLCOLORDLG:
    return (long)GetStockObject(BLACK_BRUSH);


みなさま、どうもありがとうございました。

シャノン 2005/06/26(日) 20:50:15
> dairygoods さん、R2 さん

ぬう、そんな秘密があったとは。
役立たずで申し訳ありませんでした。

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