翻译 《The Old New Thing》 - Rotating the Z-order

Rotating the Z-order - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20030826-00/?p=42793

Raymond Chen 2003年8月26日

简要

《Rotating the Z-order - The Old New Thing》,由Raymond Chen在2003年8月26日发表。文章讨论了在设计对话框时可能会遇到的一个问题:为了使点击测试(hit-testing)工作正常,控件需要按照一种Z顺序排列,但为了使键盘的Tab顺序正确,又需要另一种顺序。文章通过一个简化的对话框模板示例来解释这个问题,并提出了一种解决方案。


有时候你会碰到这样的情况:为了让点击测试工作正常,你需要按照一种Z顺序排列控件,但为了让键盘的Tab顺序工作正常,你又需要另一种顺序。

例如,看看这个为了说明问题而简化的对话框模板。

cpp 复制代码
//
//  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

对话框看起来是这样的:

复制代码
  _______  _______
 / Tab   \/ Tab   \_____________________
|                                       \
| +-[List]-----------------------------+ |
| |                                    | |
| |                                    | |
| |                                    | |
| |                                    | |
| +------------------------------------+ |
|________________________________________|
[ Import ]   [ Export ]  [ Remove ]  [ Close ]

拖放操作会调用WindowFromPoint()来确定哪个窗口接收放置。Z顺序最顶端的窗口(在对话框模板的开始处)会被选中。

我们希望放置操作到ListView,而不是Tab控件,因此ListView(IDC_LIST)需要排在Tab控件(IDC_TAB)之前。

然而,这样做破坏了可访问性,因为Tab顺序也遵循Z顺序。因此,对话框上的Tab顺序是:

List -> Tab -> Import -> Export -> Remove -> Close

这是一个不理想的Tab顺序,因为它导致焦点向上跳转(从List到Tab)。为了使Tab顺序正确,你需要将Tab放在List之前。

这就是旋转发挥作用的地方。

首先,按照Tab顺序在页面上放置控件。

Tab -> List -> Import -> Export -> Remove -> Close

记住,Tab顺序是循环的。当你在最后一个控件上按下Tab键时,你会跳转到第一个控件。所以你实际上应该将Tab顺序视为一个圆:

复制代码
   /-->  Tab  ---\
   |             |
  Close          v
   ^            List
   |             |
  Remove         v
   ^            Import
   |             |
   \-- Export <--/

一旦你这样看待它,你就会意识到你可以旋转这个圆,而Tab顺序仍然不变。所以让我们旋转它,让List首先出现,因为我们需要List在Z顺序中排在最前面。

复制代码
复制代码
   /-->  List ---\
   |             |
  Tab            v
   ^            Import
   |             |
  Close          v
   ^            Export
   |             |
   \-- Remove <--/

现在,将圆切开,得到线性图:

复制代码
List -> Import -> Export -> Remove -> Close -> Tab

这给了我们最终的对话框模板:

cpp 复制代码
//
//  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

现在你得到了两全其美的结果。List位于Z顺序的顶端,而Tab顺序仍然是正确的。✌

相关推荐
oscar99919 小时前
Memurai:Redis官方认可的Windows原生解决方案
数据库·windows·redis
暖阳常伴21 小时前
Windows安装MongoDB
数据库·windows·mongodb
星辰引路-Lefan21 小时前
全平台 Docker 部署 CPA(CLIProxyAPI Plus) 灵活定制指南 (Linux/Windows)——接入Codex
linux·windows·docker·ai·ai编程
YQ_011 天前
Windows + Ubuntu 双系统安装:不使用 GRUB,直接在开机时选择系统
linux·windows·ubuntu
小王不爱笑1321 天前
Java List 集合全面解析:ArrayList、LinkedList 与 Vector 的深度对比
java·windows·list
※※冰馨※※1 天前
【QT】System error #1455: 页面文件太小,无法完成操作
开发语言·windows·qt
武藤一雄1 天前
WPF Command 设计思想与实现剖析
windows·微软·c#·.net·wpf·.netcore
EnCi Zheng1 天前
P1B-Python环境配置基础完全指南-Windows系统安装与验证
开发语言·windows·python
John_ToDebug1 天前
WaitableEvent 跨线程等待的死锁陷阱
windows·笔记·死锁
李长渊哦1 天前
PostgreSQL 18 本地部署与运维完全指南 (Windows版)
运维·windows·postgresql