Content-Length: 8424 Content-Type: text/html
The basis of tabbing is the ability to enumerate all of the children of a particular window. The WinBeginEnumWindows() API will begin an enumeration. You provide it with the window whose children it is to enumerate. It will return you a handle, which it uses to maintain an internal state table for the enumeration session. Once you have an enumeration handle you can use WinGetNextWindow() to get each successive child window handle. When done, you use WinEndEnumWindows() to close the enumeration handle. WinGetNextWindow() will return a nul handle when it hits the end of the list.
The Z-order of the child windows drives the iteration process. In other words, the windows are enumerated in their defined Z- order. This is why the order of creation of controls in the dialogs is important for the desired tabbing order, as you will see in the next section.
Window enumeration is a fundamental type of magic that is behind many cool utilities that show you the hierarchical arrangements of any process' windows. You can use it to good effect sometimes, so check it out.
Tabbing Enumeration
Tabbing is accomplished via the WinEnumDlgItem() API. This API is not magical in any way, and just builds upon the basic window enumeration system discussed above. It effectively just enumerates the child controls of a particular window, queries their styles, and looks for WS_TABSTOP and WS_GROUP style bits to decide what to do. It can answer questions like, "From the current focus window, what is the first/last control in the next/previous group" or "From this particular window, what is the next window that has the tabstop style" or "What is the next/previous window in the same group". The tabstop and group styles really have no other use, so they are often not used when you create controls manually. But, if you want to provide tabbing for manually created controls, you must apply them.
As is often times the case in PM, the Dlg part of the name in WinEnumDlgItem() is a misnomer. It is called that because that's all OS/2 itself uses it for. However, you can use it on your own frame windows, non-modal dialogs, or on the children of your client window, to easily provide tabbing without having to use dialog processing. You always call it with a parent window whose children it is to enumerate, so there is no ambiguity about what window it is operating on.
When a dialog is loaded, the loading code will create the controls in the order they are found in the dialog definition, giving each one HWND_BOTTOM as the z-order. This effectively stacks the controls up in the same order as they were drawn by the dialog editor (or manually written by you into a dialog definition.) When you want to provide tabbing for your own manually created controls, you just need to make sure to create them in the correct order and give them the desired tab stop and group styles, just as though you would have done them in a dialog editor.
Doing It Yourself
If you want to provide your own tabbing, I would suggest that you write a single function, say bDoTab() or something similar, that is just a wrapper around WinEnumDlgItem(). That way, in every application, you can just put a call to it in your client window's WM_CHAR message handling. It will look at the character and see if it is a tab or arrow key or Alt-mnemonic character. If so, it will do the enumeration and move the focus to the new focus window, returning TRUE to say it handled the message. The WM_CHAR code should then just return TRUE to say it was handled. Otherwise, it returns FALSE and the WM_CHAR code should pass it on to the default handler or eat it or process it as needed. The type of character (tab, back tab, up, down, left, right) controls the third parameter to WinEnumDlgItem(). This parameter is one of the EDI_xxxxx values, which tell WinEnumDlgItem() what kind of enumeration to do.
To really work like dialogs do, you also need to check for mnemonics. So, if the Alt key is pressed and the WM_CHAR message is a character message, you should enumerate the child windows and send each one a WM_MATCHMNEMONIC message. If a control responds back saying that it matches the mnemonic character, put the focus on that control.
If the character is an Enter key, then enumerate the children and send each one the WM_QUERYDLGCODE message. This will cause the child window to return a set of DLGC_xxxx bit values. You just need to look for one that has the DLGC_DEFAULT bit on and send it a BM_CLICK message. This will cause that default button to send a WM_COMMAND message as though the user clicked on it.
There are some more obscure features you might have to deal with to get exactly the same results as a dialog but those are the most common ones and should serve most apps. And some of the dialog processing, as mentioned above, is not desirable for a normal window anyway. Of course, if you are doing a class library, then the tabbing support should probably be implemented in the basic window class so that all windows can optionally provide tabbing for their children. In my class library, the TWindow class has an 'autotab' attribute. If set, it calls its internal tabbing support wrapper function. This makes it trivial to provide tabbing any time its desired. If the character input causes a tab operation, then the window is not even bothered by telling any input occurred so the support is transparent and automatic
Copyright Notice
| Reply to Author
| Search
| Section Index
| Previous Page
| Next Page
If you see a problem with this web site, contact
edm2_eds@iqpac.com.