1
votes

I have a window with 10 child edit controls in it. I would like to move from one edit control to other by pressing the tab key - how do I do this?

I mean, even if I could find out whether I pressed the tab-key, how do I find the next edit control to focus into? I hope I do not have to keep track of the edit controls myself as I already added them to the parent window.

PS: by "next" I mean the order I created the edit controls...

Edit: I'm on Win32 using plain C.

Edit 2: sample



#include 

#define NAME "test"

LRESULT CALLBACK WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    HWND edit1, edit2;
    switch (msg)
    {
        case WM_CREATE:
            edit1 = CreateWindow("edit", "", WS_CHILD|WS_VISIBLE, 0, 0, 200, 50, hWnd, NULL, NULL, NULL);
            edit2 = CreateWindow("edit", "", WS_CHILD|WS_VISIBLE, 250, 0, 200, 50, hWnd, NULL, NULL, NULL);
            return 0;

        case WM_CLOSE:
            DestroyWindow(hWnd);
            return 0;

        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
    }
    return DefWindowProc(hWnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
    WNDCLASS wc;
    wc.style = 0;
    wc.lpfnWndProc = WinProc;
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hInstance = hInstance;
    wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
    wc.lpszMenuName = NAME;
    wc.lpszClassName = NAME;
    RegisterClass(&wc);

    HWND win;
    win = CreateWindow(NAME, "test", WS_OVERLAPPEDWINDOW, 0, 0, 500, 500, NULL, NULL, hInstance, NULL);

    ShowWindow(win, nCmdShow);
    UpdateWindow(win);

    MSG msg;
    while(GetMessage(&msg, NULL, 0, 0) > 0)
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;

}

2
From a raw C Windows programming standpoint - Isn't the tab order the same order as they are added to the window (the z-order)? Did you try placing your cursor in one and pressing tab?user113476
Yes, I did, it stays in the same control.Lars Kanto
If you are using a dialog then this may help - stackoverflow.com/questions/50236/…user113476
No, I don't. It's just a simple main window.Lars Kanto
Can you show some code for this?t0mm13b

2 Answers

3
votes

The dialog manager does a lot of this for you, so if you don't have a good reason for creating your own window class, you might consider creating a dialog instead.

If you're still of a mind to roll your own, you'll have to intercept WM_CHAR and look for VK_TAB and VK_SHIFT | VK_TAB. The dialog manager uses something called "z-order" as the tab order (http://msdn.microsoft.com/en-us/library/ms632599%28VS.85%29.aspx#zorder).

FWIW, my advice would be to not underestimate the burden you're taking on when trying to re-create an existing facility in Windows like this. For every behavior that you know about, there are usually at least as many that you don't. For example, how will your application behave on a pen-based device? What about accessibility extensions? Will screen readers be able to handle it properly? All of that stuff is already baked into the dialog manager.

I'm not sure I followed... I thought dialogs are just a floating windows above the "regular" (?) one. Is it possible that the application uses just a dialog, instead of proper CreateWindow()?

Dialogs can be modal or modeless children of the main application window, but they can also be the main application window. That's typically called a dialog-based app.

If you want a dialog-based application (that is, an application with a dialog as it's main window), you'd do something like this:

int WINAPI WinMain( HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nCmdShow )
{
    MSG msg;
    HWND hDlg = CreateDialog(hInst, MAKEINTRESOURCE(IDD_DIALOG1), NULL, DialogProc);
    if (hDlg != NULL)
    {
        ShowWindow(hDlg, SW_SHOWNORMAL);

        while (GetMessage(&msg, NULL, 0, 0)) {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
    return 0;
}

The full example is probably too long to list here, but if you Google for CreateDialog, you should find some examples of this.

...And is it possible to add other windows inside a dialog? Even with custom window procedures? (In other words, in dialogs, am I not restricted just to the default controls, like edit and static?)

Yes, you can create custom controls within the dialog. Within the DIALOG portion of your .rc file, you can include something like:

CONTROL "",IDC_MYCUSTOM,"MyCtrlClassName",WS_TABSTOP,10,20,30,40

You can also create a new control and add it to the dialog dynamically (I'll let you Google for an example).

Also, if I wanted to roll my own, how do I find out what's the next control? I don't really think there will be more use cases than a basic desktop

Use GetNextDlgTabItem() if you want to cycle through the controls within a dialog in tab-order: http://msdn.microsoft.com/en-us/library/ms645495%28VS.85%29.aspx

If you're rolling your own, then you probably want something like the EnumChildWindows() function: http://msdn.microsoft.com/en-us/library/ms633494%28VS.85%29.aspx

This may also be useful: http://msdn.microsoft.com/en-us/library/bb775501%28VS.85%29.aspx

0
votes

This kind of processing can be easily added to an application :- Add a call to IsDialogMessage() in your message loop - all the controls have to have the WS_TABSTOP style.

The parent window might have to be of the dialog class as the dialog window class stores state allowing it to (for example) restore focus to the correct control when activation is lost and restored.