Link to home
Start Free TrialLog in
Avatar of dirtdart
dirtdart

asked on

Tabstops

I am working with VC++ 5.0 on a Win98 system, but have run into this same problem on a Win95 machine.  When I create a window and a group of controls on that window with the following code:

HWND hWnd = CreateWindowEx(WS_EX_NOPARENTNOTIFY, "RegScreen", "Install Pro 1.0", WS_VISIBLE | WS_CAPTION | WS_BORDER | WS_SYSMENU, pt.x, pt.y, 500, 400, NULL, NULL, hInst, NULL);

CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_TABSTOP | WS_CHILD | WS_BORDER| WS_VISIBLE | ES_LEFT, 165, 45, 305, 27, hWnd, (HMENU)IDC_USERNAME, hInst, NULL);

CreateWindowEx(WS_EX_CLIENTEDGE, "EDIT", "", WS_TABSTOP | WS_CHILD | WS_BORDER| WS_VISIBLE | ES_LEFT, 165, 93, 305, 27, hWnd, (HMENU)IDC_COMPANY, hInst, NULL);      

CreateWindow("BUTTON", "<< Back", WS_TABSTOP | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 210, 325, 65, 27, hWnd, (HMENU)IDC_BACK, hInst, NULL);

CreateWindow("BUTTON", "Next >>", WS_TABSTOP | WS_DISABLED | WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 275, 325, 65, 27, hWnd, (HMENU)IDC_NEXT, hInst, NULL);

CreateWindow("BUTTON", "Cancel", WS_TABSTOP | WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, 410, 325, 65, 27, hWnd, (HMENU)IDC_CANCEL, hInst, NULL);

Why is it that the Tab button COMPLETLY REFUSES to work under any circumstances?  I was under the impression that if all the controls were created with the WS_TABSTOP style that the tab key would move between them.  However this does not happen on the window that I have created.
Avatar of Answers2000
Answers2000

I think...

The parent window for the controls needs to handle the WM_NEXTDLGCTL message.  The reason you don't need to include this code for dialog boxes, is that the default dialog procedure (DefDlgProc) handles this by default.  In your case, your parent window isn't a dialog, so you have to put in this code yourself in the parent window (the one you create first).

BTW if you are thinking of changing to use a dialog/modeless dialog box for the parent, watch out - I seem to recall that DefDlgProc only handles WM_NEXTDLGCTL message correctly for controls that are in the dialog's resource template at least under some versions of Windows.  Sorry I can't be more specific on this (extra) comment, as I simply don't remember too well!
Avatar of dirtdart

ASKER

Well, this seems like a logical answer, but I'm going to need a bit more information before I can grade it.  I attempted to process the message with what little information I can find on it in the Win32 SDK, but it certainly didn't work in the way I need it to.  My code:

case WM_NEXTDLGCTL:
      {
            SetFocus(GetDlgItem(hWnd, wParam));
            return 0;
      }

Since wParam supposedly returns the ID of the control that should receive focus, this seems to be a logical conclusion.  Whenever the Tab is pressed, it fires the message and the message pump sets the focus to the next provided control.  However.  When run, the above code simply prevents any of the controls on the form from receiving focus.
Well, I've waited two weeks for more of an explination, so I guess now I'll have to open the question back up.
ASKER CERTIFIED SOLUTION
Avatar of SaGS
SaGS

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Well, that looks great, and it certainly answers my question.  However, I'd appreciate it if you'd give me one more piece of advice to go with this.  My main message loop processes messages for at least 12 different windows (kind of a wizard type thing).  How do I tell which window handle is currently being processed so that I can pass it to IsDialogMessage?
The key is the WM_ACTIVATE message. Define a global variable:

HWND hActiveWnd = NULL;

and inside all windows procedures (in fact, it's enough to do this only for windows that need the extra processing) handle the WM_ACTIVATE message. When the window is activated (WA_ACTIVE, WA_CLICKACTIVE), store the window's handle into the global variable; when deactivated (WA_INACTIVE), set the global handle to NULL (Windows takes care to send these messages in the proper order - first deactivates the old window, then activates the new one). In the main message loop, examine the global variable to decide what to do (NULL => nothing to do, the active win does not belong to your app or needs nothing special, !=NULL => your window, the value is the active window's HWND).

Note: You can use a similar trick to implement a window-specific accelerators table (a global "HACCEL hActiveWndAccel = NULL;", and so on).
Sounds great.  Thanks for all the help.  Now maybe I can get this junk finished!