摘要
基于 Windows 的应用程序通常会显示数据输入对话框,用于向用户请求信息。 这些对话框可能包含多个编辑控件和两个命令(推送)按钮,标记为 "确定" 和 "取消"。 "数据输入" 对话框的一个示例是请求来自用户的个人信息,如社会保险号、地址、标识(ID)号码、日期/时间等。 其中每个项都输入到一个编辑控件中。默认情况下,在对话框中使用 TAB 键在编辑控件之间移动焦点。 但是,作为常见的用户界面,还可以使用 ENTER (RETURN)键在编辑控件之间移动(例如,用户输入一条信息后,按 ENTER 将焦点移到下一个字段)。有几种方法可以使用 ENTER 键在编辑控件之间移动。 一种方法是在编辑控件和按钮的对话框中使用 WM_COMMAND 和附带的通知消息。 另一种方法涉及对编辑控件进行子类分类。 第三个涉及使用应用 Studio 和类向导,并创建新的对话框成员函数。
更多信息
方法 I:(WM_COMMAND)
此方法基于对话框的以下行为(对话框管理器)和 Windows 中的焦点处理。如果对话框或其控件的其中一个当前具有输入焦点,则按 ENTER 键会导致 Windows 发送 WM_COMMAND 消息,其中 idItem (并用 wparam 参数)参数设置为默认命令按钮的 ID。 如果对话框没有默认的命令按钮,则默认情况下将 idItem 参数设置为 IDOK。当应用程序收到 idItem 设置为默认命令按钮 ID 的 WM_COMMAND 消息时,在按 ENTER 键之前,焦点将保留在具有焦点的控件上。 在此点调用 GetFocus ()返回在按 ENTER 键之前获得焦点的控件的句柄。 应用程序可以检查此控制句柄并确定其是否属于对话框中的任何编辑控件。 如果是,则用户将数据输入到其中一个编辑控件中,然后在执行此操作后按 ENTER。 此时,应用程序可以将 WM_NEXTDLGCTL 消息发送到对话框,以将焦点移动到下一个控件。但是,如果焦点使用其中一个命令按钮(取消或确定),则 GetFocus ()将返回一个按钮控制句柄,此时,点1可以关闭该对话框。 此逻辑的伪代码类似于应用程序的对话框过程中的以下代码:
case WM_COMMAND: if(wParam=IDOFDEFBUTTON || IDOK) { // User has hit the ENTER key. hwndTest = GetFocus() ; retVal = TesthWnd(hWndTest) ; //Where retVal is a boolean variable that indicates whether //the hwndTest is the handle of one of the edit controls. if(hwndTest) { //Focus is with an edit control, so do not close the dialog. //Move focus to the next control in the dialog. PostMessage(hDlg, WM_NEXTDLGCTL, 0, 0L) ; return TRUE ; } else { //Focus is with the default button, so close the dialog. EndDialog(hDlg, TRUE) ; return FALSE ; } } break ;
方法 II
此方法涉及对对话框中的 "编辑" 控件进行子类/superclassing。 编辑控件是子类或 superclassed 后,无论对话框是否具有默认命令按钮,所有键盘输入都将发送到当前具有输入焦点的编辑控件的子类/超类过程。 应用程序可以捕获键消息(或 char)消息,查找 ENTER 键,并相应地进行处理。 下面是一个示例子类过程,用于查找 ENTER 键:
//*------------------------------------------------------------------- //| Title: //| SubClassProc //| //| Parameters: //| hWnd - Handle to the message's destination window //| wMessage - Message number of the current message //| wParam - Additional info associated with the message //| lParam - Additional info associated with the message //| //| Purpose: //| This is the window procedure used to subclass the edit control. //*--------------------------------------------------------------------- long FAR PASCAL SubProc(HWND hWnd, WORD wMessage,WORD wParam,LONG lParam) { switch (wMessage) { case WM_GETDLGCODE: return (DLGC_WANTALLKEYS | CallWindowProc(lpOldProc, hWnd, wMessage, wParam, lParam)); case WM_CHAR: //Process this message to avoid message beeps. if ((wParam == VK_RETURN) || (wParam == VK_TAB)) return 0; else return (CallWindowProc(lpOldProc, hWnd, wMessage, wParam, lParam)); case WM_KEYDOWN: if ((wParam == VK_RETURN) || (wParam == VK_TAB)) { PostMessage (ghDlg, WM_NEXTDLGCTL, 0, 0L); return FALSE; } return (CallWindowProc(lpOldProc, hWnd, wMessage, wParam, lParam)); break ; default: break; } /* end switch */
方法 3
此方法涉及使用应用 Studio 和 ClassWizard 并创建新的对话框成员函数。此方法将允许用户按 ENTER 键,并将焦点移动到下一个编辑控件。 如果焦点当前位于对话框中的最后一个编辑控件上,则焦点将前进到第一个编辑控件。首先,使用应用 Studio 更改对话框的 "确定" 按钮的 ID。 应用 Studio 的默认行为是将 "确定" 按钮提供 ID IDOK。 "确定" 按钮的 ID 应更改为另一个值,如 "IDC_OK"。 此外,更改 "确定" 按钮的属性,以使其不是默认的按键。接下来,使用 ClassWizard 创建新的对话框成员 funciton。 将新的成员函数命名为类似 OnClickedOK 的内容。 此函数应绑定到 IDC_OK 控件中的 BN_CLICKED 消息。完成此操作后,编写 OnClickedOK 函数的主体。 应将你通常放在 OnOK 函数中的代码放入新的 OnClickedOK 函数中,包括类的 OnOK 函数。将以下原型添加到对话框的头文件中:
protected: virtual void OnOK();
将 OnOK 函数添加到对话框,代码如下所示:
void CMyDialog::OnOK() { CWnd* pwndCtrl = GetFocus(); CWnd* pwndCtrlNext = pwndCtrl; int ctrl_ID = pwndCtrl->GetDlgCtrlID(); switch (ctrl_ID) { case IDC_EDIT1: pwndCtrlNext = GetDlgItem(IDC_EDIT2); break; case IDC_EDIT2: pwndCtrlNext = GetDlgItem(IDC_EDIT3); break; case IDC_EDIT3: pwndCtrlNext = GetDlgItem(IDC_EDIT4); break; case IDC_EDIT4: pwndCtrlNext = GetDlgItem(IDC_EDIT1); break; case IDOK: CDialog::OnOK(); break; default: break; } pwndCtrlNext->SetFocus(); }