Sometimes you run into a conflict where you need the controls laid out in one Z-order to get hit-testing to work, but need a different order to get keyboard TAB order working.
For example, consider this dialog template, which has been simplified for expository purposes.
//////////////////////////////////////////////////////////////////////// // // Note: The ListView control has to be listed BEFORE the tab control in // order for drag-drop to work properly. // IDD_MAIN DIALOGEX 0, 0, 335, 270 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_CONTEXTHELP | DS_SHELLFONT CAPTION "Blah blah" FONT 8, "MS Shell Dlg" BEGIN CONTROL "List",IDC_LIST,WC_LISTVIEW,LVS_REPORT | WS_BORDER | WS_TABSTOP | LVS_SHOWSELALWAYS,15,46,305,111 CONTROL "Tab",IDC_TAB,WC_TABCONTROL, WS_TABSTOP,7,24,321,141 PUSHBUTTON "&Import...",IDC_IMPORT,7,172,51,14 PUSHBUTTON "&Export...",IDC_EXPORT,62,172,51,14 PUSHBUTTON "&Remove",IDC_REMOVE,117,172,51,14 DEFPUSHBUTTON "&Close",IDOK,277,249,51,14 END
The dialog looks like this:
_______ _______ / Tab \/ Tab \_____________________ | \ | +-[List]-----------------------------+ | | | | | | | | | | | | | | | | | | +------------------------------------+ | |________________________________________| [ Import ] [ Export ] [ Remove ] [ Close ]
Drag/drop will call WindowFromPoint() to determine which window receives the drop. The window closest to the top of the Z-order (towards the beginning of the dialog template) will be chosen.
We want drops to go to the listview, not the tab control, so the ListView (IDC_LIST) needs to go ahead of the Tab control (IDC_TAB).
However, doing this breaks accessibility, because the tab order follows the Z-order, too. Consequently, the Tab order on the dialog is
List -> Tab -> Import -> Export -> Remove -> Close
This is an undesirable tab order, since it causes focus to jump upwards (from List to Tab). To get the tab order right, you need to put Tab before List.
This is where rotation comes in.
Start by putting the controls on the page in the order necessary for tabbing.
Tab -> List -> Import -> Export -> Remove -> Close
Recall that the tab order is circular. When you are on the last control and hit TAB, you go to the first one. So you really should view the tab order as a circle:
/--> Tab ---\ | | Close v ^ List | | Remove v ^ Import | | \-- Export <--/
Once you view it this way, you realize that you can rotate the circle and the tab order remains unchanged. So let’s rotate it so List comes first, since we need List to come first in the Z-order.
/--> List ---\ | | Tab v ^ Import | | Close v ^ Export | | \-- Remove <--/
Now cut the circle open, yielding the linear diagram:
List -> Import -> Export -> Remove -> Close -> Tab
This gives us our final dialog template:
//////////////////////////////////////////////////////////////////////// // // Note: The ListView control has to be listed BEFORE the tab control in // order for drag-drop to work properly. // IDD_MAIN DIALOGEX 0, 0, 335, 270 STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU | DS_CONTEXTHELP | DS_SHELLFONT CAPTION "Blah blah" FONT 8, "MS Shell Dlg" BEGIN CONTROL "List",IDC_LIST,WC_LISTVIEW,LVS_REPORT | WS_BORDER | WS_TABSTOP | LVS_SHOWSELALWAYS,15,46,305,111 PUSHBUTTON "&Import...",IDC_IMPORT,7,172,51,14 PUSHBUTTON "&Export...",IDC_EXPORT,62,172,51,14 PUSHBUTTON "&Remove",IDC_REMOVE,117,172,51,14 DEFPUSHBUTTON "&Close",IDOK,277,249,51,14 CONTROL "Tab",IDC_TAB,WC_TABCONTROL, WS_TABSTOP,7,24,321,141 END
Now you get the best of both worlds. List is at the top of the Z-order, and the tab order is still correct.
0 comments