Tab 顺序辅助类





3.00/5 (2投票s)
用于在子对话框中操作 tab 顺序的类
引言
在 Windows 应用程序中,您可以通过按 Tab 键来更改控件的焦点。Tab 顺序是指按 Tab 键时焦点的序列。
从 Visual C++ 6.0 的资源编辑器中,您可以通过按 Ctrl+D 键来查看和更改 Tab 顺序。
在简单的对话框中,Tab 顺序很容易使用。但是,在复杂对话框(例如多子对话框环境)中,Tab 顺序不能正常工作。焦点在一个对话框中移动,永远不会移动到子对话框。
复杂对话框
总而言之,Tab 顺序工作正常,而且非常简单。但是,当您创建子对话框时,问题就会发生。让我们想象一个对话框,它有三个按钮和一个子对话框。子对话框有两个按钮。在这种情况下,预期的 Tab 序列如下
1. Main Dialog Button 1
2. Main Dialog Button 2
3. Main Dialog Button 3
4. Sub Dialog Button 1
5. Sub Dialog Button 2
但是,如果没有额外的 Tab 键处理,我们无法通过 Tab 键将焦点设置到子对话框,它的工作方式是 1 > 2 > 3 > 1 > 2 > 3...
CFocusEx
类解决了这个问题。它将错误的焦点序列(1 > 2 > 3 > 1 > 2 > 3...)更改为预期的序列(1 > 2 > 3 > 4 > 5 > 1 > 2 > 3...)。
工作原理
CFocusEx
简单而灵活。此外,它支持大多数具有多个子对话框的应用程序。当用户按下 Tab 键时,CFocusEx
会比较注册窗口和焦点窗口。CFocusEx
类按照注册的顺序移动控件的焦点。如果下一个焦点控件是对话框,它会将焦点设置在该对话框的第一个控件上。
Using the Code
- 重写父对话框的
PreTranslateMessage
函数来拦截 Tab 键的事件。 - 声明
CFocusEx
对象作为类成员变量,并声明GetFocusableWindow
函数以管理 Tab 顺序class CFocusDlg : public CDialog { // Construction public: CFocusDlg(); . . . private: static HWND GetFocusableWindow(int nPosition, LPVOID lParam); CFocusEx m_objFocus; };
- 初始化
CFocusEx
对象并调用ProcessKeyPressMessage
来处理键盘事件。CFocusEx::InitFocusEx
的第一个参数是GetFocusableWindow
函数。这是一个非常重要的函数,因为它决定了下一个焦点。BOOL CFocusDlg::PreTranslateMessage(MSG* pMsg) { m_objFocus.InitFocusEx( GetFocusableWindow, this ); if( m_objFocus.ProcessKeyPressMessage( this, pMsg ) ) { return TRUE; } return CDialog::PreTranslateMessage(pMsg); }
- 编写
GetFocusableWindow
函数以确定下一个焦点。您可以根据nPosition
的数据分配适当的句柄来接收焦点。
通常,您可以像以下代码一样编写父对话框的GetFocusableWindow
。m_dlgSub
是在最后一个控件之后获得焦点的子对话框。HWND CFocusDlg::GetFocusableWindow(int nPosition, LPVOID lParam) { CFocusDlg* pThis = (CFocusDlg*)lParam; switch( nPosition ) { case FOCUSABLEWINDOW_POSITION_FIRST: { return CFocusEx::GetFirstFocusableWindow ( pThis->GetSafeHwnd() ); } break; case FOCUSABLEWINDOW_POSITION_FOCUSABLE: { return pThis->m_dlgSub.GetSafeHwnd(); } break; case FOCUSABLEWINDOW_POSITION_LAST: { return CFocusEx::GetLastFocusableWindow ( pThis->GetSafeHwnd() ); } break; } return NULL; }
该函数有三种 switch 状态:
FOCUSABLEWINDOW_POSITION_FIRST
或FOCUSABLEWINDOW_POSITION_LAST
返回第一个或最后一个控件的句柄。FOCUSABLEWINDOW_POSITION_FOCUSABLE
是函数最重要的部分。
当用户在控件的末尾按下 Tab 按钮时,将使用FOCUSABLEWINDOW_POSITION_FOCUSABLE
调用该函数。因此,有两种情况需要考虑。 -
首先,将焦点从父窗口设置到子窗口。返回父窗口的句柄,将焦点设置到父窗口。
-
其次,将焦点从子窗口设置到父窗口。返回子窗口的句柄,将焦点设置到子窗口。
- 重写子对话框的
PreTranslateMessage
函数来拦截 Tab 键的事件。 - 声明
CFocusEx
对象作为类成员变量,并声明GetFocusableWindow
函数以管理 Tab 顺序class CFocusSubDlg : public CDialog { // Construction public: CFocusSubDlg(); . . . private: static HWND GetFocusableWindow(int nPosition, LPVOID lParam); CFocusEx m_objFocus; };
- 初始化
CFocusEx
对象BOOL CFocusSubDlg::PreTranslateMessage(MSG* pMsg) { m_objFocus.InitFocusEx( GetFocusableWindow, this ); if( m_objFocus.ProcessKeyPressMessage( this, pMsg ) ) { return TRUE; } return CDialog::PreTranslateMessage(pMsg); }
- 编写
GetFocusableWindow
函数以确定下一个焦点。
通常,您可以像以下代码一样编写子对话框的GetFocusableWindow
HWND CFocusDlg::GetFocusableWindow(int nPosition, LPVOID lParam) { CFocusDlg* pThis = (CFocusDlg*)lParam; switch( nPosition ) { case FOCUSABLEWINDOW_POSITION_FIRST: { return CFocusEx::GetFirstFocusableWindow ( pThis->GetSafeHwnd() ); } break; case FOCUSABLEWINDOW_POSITION_FOCUSABLE: { if( pThis->GetParent() ) { if( pThis->GetParent()->GetParent() ) { return pThis->GetParent()-> GetParent()->GetSafeHwnd(); } } } break; case FOCUSABLEWINDOW_POSITION_LAST: { return CFocusEx::GetLastFocusableWindow ( pThis->GetSafeHwnd() ); } break; } return NULL; }
就这样。如果您不理解本文中的代码,则附加项目的代码将更容易理解。
历史
- 2009 年 10 月 13 日:初始版本