⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 07.6 输入焦点的传递.txt

📁 网上第一本以TXT格式的VC++深入详解孙鑫的书.全文全以TXT格式,并每一章节都分了目录,清晰易读
💻 TXT
📖 第 1 页 / 共 2 页
字号:
7.6 输入焦点的传递
现在,我们打开 Mybole程序的测试对话框,在第一个编辑框中输入文字,然后按下回车键,这时会发现这个对话框被关闭了。我们在对话框资源界面中查看该对话框上 OK按钮的属性,将会发现它的 E是: IDOK ot)]换到J Styles选项卡,可以看到它的 Default button 选项是选中的(如图 7 .40所示),再查看其他按钮的属性,发现它们都没有选中此选项,说明这个 OK按钮是测试对话框的默认按钮。实际上,当在对话框中按下回车键时,会选
择对话框中默认按钮的消息响应函数来处理这一
事件,而基类 CCDialog)的 IDOK按钮的默认响
应的功能就是关闭对话框。因此,
这时我们一旦在 Mybole程序的测试对话框中按下
回车键,这个对话框就被关闭了。
图 7 .40 IDOK按钮的属性对话框
我们希望实现的功能是:当在第一个编辑框中
按下回车键后,将输入焦点转移到第二个编辑框。为了屏蔽掉到默认的回车键关闭对话框这一功能,应该在对话框子类(本例中是指 CT.stDlg类〉中重写 OK按钮的消息响应函数。因此,在 Mybole程序中,应该为测试对话框中的 IDOK按钮添加鼠标单击消息响应函数。一种添加方法是直接在 IDOK按钮上双击鼠标左键,并接受系统提供的默认函数名称: OnOK,例 7-30是这个函数的原始定义代码。
侈IJ 7-30 

void CTestDlg : :OnOK(} 
11 TODO : Add extra validation here 

CDialog: : OnOK(} ; 
从上述例 7 -30所示代码可以看到,默认情况下,对话框子类重写的 IDOK按钮的响应函数仍调用了基类的 OnOK函数。为了实现按下回车键时不关闭对话框这一功能,应该在此重写函数中将调用基类的 OnOK函数这条语句注释起来。然后, Build井运行 Mybole程序,打开测试对话框,把输入焦点移到第一个编辑框中,接着按下回车键,发现此时对话框并没有被关闭了。可见,默认按钮关闭对话框这一问题解决了。
下面,我们要实现当在测试对话框中的第一个编辑框中按下回车键后,输入焦点被转移到第二个编辑框这一功能。这可以通过捕获键盘按键消息,然后在此消息响应函数中把输入焦点移动到下一编辑框控件来实现。这有两种实现方式,一种是为编辑框控件生成一个相关联的类,然后利用这个类来捕获键盘按键消息。另一种方式是修改编辑框控件的窗口过程函数,也就是说,自己编写一个编辑框控件的窗口过程,然后替换 MFC提供的默认的编辑框控件窗口过程函数。我们知道,窗口的所有消息都要到该窗口的窗口过程函数中来报道。因此,在这个新过程函数中可以进行一个判断,如果当前到来的是一个字符消息,井且该字符是一个回车符,那么就将输入焦点移动到一下编辑框控件。根据前面的知识,我们知道,窗口过程是在定义窗口类时设置的。那么当一个窗口已经创建之后,如何去修改该窗口己指定的过程函数呢?这可以通过调用 SetWindowLong函数来实现。该函数的原型声明如下所示: 
LONG SetWindowLong(HWND hWnd , int nIndex, LONG dwNewLong ); 
该函数的作用是改变指定窗口的属性,它的各个参数的意义如下所述: 
. hWnd 
指定想要改变其属性的窗口句柄。 
. nIndex 
指定要设置的属性值的偏移地址。其取值可以取表 7.4中所列各值。
表 7 .4 nlndex参数取值之一

取值 意义  
GWL_EXSTYLE  设置一个新的扩展窗口风格  
GWL_STYLE  设置一个新的窗口风格  
GWL_ WNDPROC  设置一个新的窗口过程  
GWL_HINSTANCE  设置一个新的应用程序实例句柄  
GWL ID  为窗口设置一个新的标识  
GWL USERDATA  设置与窗口相关的 32位值 

当 hWnd参数指定的是一个对话框,那么nIndex参数也可以取表 7.5中所列各值。
表 7.5 nlndex参数取值之二

取 值 意义  
DWL DLGPROC  设置新的对话框过程  
DWL MSGRESULT  设置在对话框过程中处理的消息返回值  
DWL USER  设置新的额外信息,该信息仅为应用程序所有,例如句柄或指针 

. dwNewLong 
指定设置的新值。
如果调用成功, SetWindowLong函数将返回先前为窗口指定的 32位整形值。也就是说,如果为指定窗口设定一个新的窗口过程,则该函数将返回先前为该窗口类指定的窗口过程的地址。因此,可以利用这个函数来修改编辑框控件的窗口过程。可是修改操作放在哪个函数中比较合适昵?可以把修改编辑框窗口过程的操作放到 WM_CREATE消息的响应函数中吗?我们知道,在响应这个消息的时候,对话框的子控件还未创建完成,只有在
此消息处理完毕之后,对话框及其子控件才全部创建完成。因此,在此消息的响应函数中

是无法获得对话框中各子控件的窗口对象的,也就无法修改编辑框控件的窗口过程函数。实际上,在程序运行时,当对话框及其上的子控件创建完成,将要显示之前会发送的一个消息: WM_INITDIALOG。因此,在此消息的响应函数中修改编辑框控件的窗口过程
比较合适。那么,首先就需要为CTestDIg类添加WM_INITDIALOG消息的响应函数。添加方法可以是:在ClassView选项卡的CTestDIg类上单击鼠标右键,从弹出的快捷菜单中选择【Add Windows Message Handler...】菜单命令,这时,会弹出如图7.41所示的添加 Windows消息和事件处理函数的对话框。在该对话框左边的消息和事件列表中选中 WM INITDIALOG消息,直接单击【Add and Edit】按钮,完成消息响应函数的添加,并跳转到该响应函数的定义处。 
 图 7.41 New Windows Message and Event Handlers for c1ass CTestDlg对话框例7-31是实现我们所需功能而自定义的编辑框窗口过程函数。例7-31 
1. WNDPROC prevProc ; 
2 . LRESULT CALLBACK NewEditProc( 
3. HWND hwnd , 	11 handle to window 

4. UINT uMsg , 	11 message identifier 

5. WPARAM wParam, 11 first message parameter 


6. LPARAM lparam 11 second message parameter 


7. ) 

8. { 

9. 	if( uMsg WM_CHAR && wparam OxOd) 


10. { 

11. ::SetFocus(GetNextWindow(hwnd, GW_HWNDNEXT)) ; 


12 . return 1; 
13. ) 

14. else 

15. { 

16. return prevProc(hwnd,uMsg , wParam, 1Param) ; 

17. } 

18. } 


上述例7-31所示代码中,首先定义一个窗口过程函数,在此函数中,截获WM CHAR 消息并作相应判断和处理。因为对于WM_CHAR消息来说,它的 wParam参数保存的是字符的ASCII码,所以,我们可以利用此参数判断当前字符是不是回车符。如果是回车符,则把输入焦点传递到下一个编辑框控件。如果不是因车符,那么就调用先前的窗口过程来处理该消息。
国际z窗口过程的函数原型比较复杂,不容易记住。实际上,我们也没有
必要去记忆它,在需要时可以查看 MSDN提供的关于 WNDCLASS结构的帮助,在其帮助页中可以找到 WindowProc函数的帮助信息,然后直接复制该函数的声明,再把函数名修改为自己的窗口过程名称即可。在程序开发过程中,很多函数并不需要记忆,只要知道如何去查找它们就可以了。
另外,设置焦点可以利用SetFocus函数来实现。因为NewEditProc这个窗口过程是全局函数,所以不能调用CWnd类的成员函数,只能使用相应的PlatfonnSDK函数。 SDK提供的SetFocus函数只有一个参数,即设置输入焦点的窗口句柄,其声明形式如下所示: 
HWND SetFocus ( ~hWnd ) ; 
如果希望获得对话框中某个控件的下一个控件的句柄,可以调用 GetNextWindow函数,当然这里也应该调用SDK提供的这个函数,其声明形式如下所示: 
HWND GetNextWindow ( HWND hWnd, UINT wCmd) ; 
这个函数将返回指定窗口的下一个窗口的句柄,它的第一个参数指定当前窗口句柄,本例中就是指测试对话框中第一个编辑框的窗口句柄。第二个参数是查找的方向,如果是 GW_HWNDNEXT,那么该函数将查找给定窗口的下一个窗口:如果是GW_HWNDPREV , 该函数返回给定窗口的上一个窗口的句柄。因为本例是要将输入焦点移动到当前编辑框控件的下一个窗口上,所以应选择GW_HWNDNEXT。
现在我们要得到第一个编辑框控件的窗口句柄,作为GetNextWindow函数的第一个参数。为此,读者可能首先想到的是调用GetD1gltem函数,注意在这里只能调用PlatfollIl SDK 提供的GetDIgltem函数,然而通过这个函数来得到编辑框控件的句柄,实现起来比较麻烦。
回顾一下我们在第一章中介绍的Windows消息运行机制。所有的窗口消息,都伴随着一个该窗口的句柄(回想一下MSG结构体〉。对消息进行处理的窗口过程的前四个参数和消息结构体 (MSG)的前四个成员变量是一致的,既然NewEditProc窗口过程是为第一个

编辑框控件服务的,那么第一个编辑框的窗口句柄也将作为参数传递给NewEditProc窗口过程函数,也就是说,NewEditProc函数的hwnd参数保存的就是第一个编辑框控件的句柄。因此, GetNextWindow函数的第一个参数可以直接使用hwnd这个参数。
当设置完输入焦点后,可以简单地让窗口过程返回数值:1,结束对回车字符的处理。然后在CTestDlg类的OnInitDialog这个消息响应函数中修改第一个编辑框的窗口过程函数,代码如例7-32所示。 
例7-32 

BOOL CTestDlg: :OnlnitDialog() 
CDialog::OnlnitDialog( ) ; 
// TODO: Add extra initialization here 

prevProc=(WNDPROC)SetWindowLong(GetDlgItem(IDC_EDIT1)->m_hWnd, 
GWL_WNDPROC ,(LONG)NewEditProc); 

return TRUE; 
// return TRUE unless you set the focus to a control // EXCEPTION: OCX Property Pages should return FALSE 
Build井运行Mybole程序,打开测试对话框,把输入焦点移到第一个编辑框中,然后按下回车键,但是将会发现输入焦点并没有像我们想像的那样移动到第二个编辑框中。这是什么原因呢?我们打开测试对话框资源,查看第一个编辑框的属性,打开其Styles选项卡,如图7.42所示。 


可以发现该编辑框控件没有选中Multiline选项,即这个编辑框不支持多行,因此就无法接收回车键按下这一消息。所以,我们应该选中这个选项,然后再测试一下程序,在第一个编辑框中按下回车键,将会发现输入焦点被转移到第二个编辑框窗口上了。
但是,如果希望当再次按下回车键时,输入焦点从第二个编辑框转移到第三个编辑框,目前是无法是实现的,因为现在只修改了第一个编辑框的窗口过程。当然,我们可以按照此方法,再修改第二个编辑框的窗口过程函数,让输入焦点往下传递。但是,显然,这种方式实现起来很不方便,后面将为读者介绍一种比较方便的方法,可以将输入焦点依次向下传递。
这里再介绍一种获得窗口句柄的方法:使用GetWindow函数来实现。该函数返回与指定窗口有特定关系的窗口句柄,其声明形式如下所示: 
HWND GetWindow(HWND hWnd,UINT uCrnd ); 
该函数的第一个参数是开始查找的窗口的句柄,第二个参数指定hWnd参数指定的窗口与要获得的窗口之间的关系,如果其取值是GW_HWNDNEXT,则该函数将查找在Z次序中位于指定窗口下面的窗口:如果其取值是GW_HWNDPREV,则该函数将查找在Z次序中位于指定窗口前面的窗口。关于nCmd参数的更多取值,请参看MSDN。我们可以试试这个的数,首先将上述例7-31所示的窗口过程函数代码中的第 11行代码注释起来,然后在其后添加例7-33所示代码中加灰思示的那行语句。 
. 
例7-33 

1. WNDPROC prevProc ; 

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -