关闭

VC 窗口焦点问题以及回车键,tab键的相关

2004人阅读 评论(0) 收藏 举报
分类:

转载自:http://blog.csdn.net/chenyujing1234/article/details/8958322


看到这篇文章写得不错,就转了下,以备后用,标明了出处。


建立一个基于对话框的应用程序,可以看到在CXxxApp的InitInstance()函数中:

    CDlgaDlg dlg;

    m_pMainWnd = &dlg;

应用程序启动时,必须对CXxxApp的成员变量m_pMainWnd进行赋值,否则无法运行。在单文档的工程中,我们看不到这种赋值操作,它是在

   if (!ProcessShellCommand(cmdInfo))

       return FALSE;

在ProcessShellCommand函数中对m_pMainWnd赋了值。

一、return false和return ture的区别:

1. 在CXxxApp的InitInstance()函数中:

return false:退出应用程序,不进入消息循环。

return ture:应用程序进入消息循环。

2. 在对话框类中的OnInitDialog()中:

return false:如果在OnInitDialog()函数中设置了某控件得到焦点,如:

      GetDlgItem(IDC_EDIT1))->SetFocus();

      应return false,否则上一句代码不会生效。

return ture:在OnInitDialog()函数中没有设置了某控件得到焦点,应return ture。

说明:要使对话框上的某个控件在一显示对话框,就具有焦点,还可以将该控件的

      Table Order设为1。

二、在对话框中响应回车键:

在对话框中回车,会执行缺省按钮(Default Button)的函数,默认的缺省按钮是IDOK。如果没有缺省按钮,会执行对话框中的OnOK()函数。所以,在一个对话框中要控制回车键,可以采用下面的方法:

1. 在OnOK()函数中添加代码:

在对话框中添加四个文本框,我们想用户按回车键时,四个文本框依次循环得到焦点:

if(GetFocus()==GetDlgItem(IDC_EDIT4))    //如果第四个文本框得到焦点

        GetDlgItem(IDC_EDIT1)->SetFocus();   //使第一个文本框得到焦点

else if (GetFocus()->GetDlgCtrlID()==IDOK)   //如果“确定”按钮得到焦点

        CDialog::OnOK();            //对话框返回

else

        GetFocus()->GetNextWindow()->SetFocus(); 

//使当前具有焦点窗口的下一个(按照Table Order顺序)窗口得到焦点

2. 添加按钮,将其设置为缺省按钮,Visible属性设为false,为它添加响应函数,在其中编程(代码类似1)。

3. 更换回调函数:

我们更换第一个文本框的回调函数,让它不响应回车键。

i.                     定义一个全局变量WNDPROC  oldProc; 用于保存原来的回调函数的指针。

ii.                   在对话框类中的OnInitDialog()中用SetWindowLong函数更换第一个文本框的回调函数为newProc

oldProc=(WNDPROC)SetWindowLong(GetDlgItem(IDC_EDIT1)->m_hWnd,GWL_WNDPROC,(long) newProc);

iii.                  定义newProc函数:

  LRESULT CALLBACK newProc (

HWND hwnd,UINT uMsg, WPARAM wParam, LPARAM lParam)

{

       if(uMsg==WM_CHAR)     //如果是字符消息

       {

              if(0xd==wParam)   //如果是回车键

                     return 1;     //不处理就返回,即不响应回车键

       }

       return oldProc (hwnd,uMsg,wParam,lParam);

              //其它消息仍由原来的回调函数处理

}

说明:此种方法要文本设置文本框的MultiLine 和Want return属性设为有效。

三、制作一个可以响应WM_MOUSEMOVE消息的按钮:

1. 新建一个类CHide ,从CButton派生,增加成员对象CHide *m_btnFriend,在类中响应WM_MOUSEMOVE消息,在OnMouseMove中添加代码:

    ShowWindow(SW_HIDE);

    m_pmyFriend->ShowWindow(SW_NORMAL);

2. 在对话框的头文件中加入#include “hide.h”

3. 为对话框上的“确定”和“取消”按钮添加捆绑变量

i.                     静态绑定:

a.       用ClassWizard为对话框上的“确定”和“取消”按钮添加捆绑变量,

     CHide             m_btnOK;

       CHide             m_btnCancel;

并将其中一个按钮的Visible属性设为false。

b.       此种方法会在对话框的DoDataExchange函数中添加

       DDX_Control(pDX, IDCANCEL, m_btnCancel);

       DDX_Control(pDX, IDOK, m_btnOK);

c.       在对话框类中的OnInitDialog()中添加代码:

     m_btnOK.m_pmyFriend=&m_btnCancel;

       m_btnCancel.m_pmyFriend=&m_btnOK;

ii.                   动态绑定:

a.       定义两个成员变量:

     CHide             m_btnOK;

       CHide             m_btnCancel;

b.       在对话框类中的OnInitDialog()中添加代码:

     m_btnOK.m_pmyFriend=&m_btnCancel;

m_btnCancel.m_pmyFriend=&m_btnOK;

m_btnOK.SubclassDlgItem(IDOK,this);

m_btnCancel.SubclassDlgItem(IDCANCEL,this);

=======================================================================================================

MFC中如何将焦点设置到指定控件上

我们常常会有这样的需求,想在窗口打开的时候就将焦点(光标)设置到某个指定的控件上去。

我们都知道设置焦点需要用到setFocus这个方法(几乎任何编程环境都这样VC,C#,VB,VF都这样)。

但在VC中我们使用了setfocus并不一定会达到我们需要的效果。

如果我们仅仅设置了setfocus那是不够的,我们需要将对话框中的OnInitDialog的最后那句return设置为FALSE;

 

我曾经在对话框中对各个控件的输入进行校验检测,当检测到不满足要求的输入则会弹出对话框提示。

我本来的目的是弹出提示框,但确定后回到窗体中后就将焦点和光标设置到对应的控件上,结果死都上不去。

 

一开始我以为是Setfocus的设置无效,后面发现是逻辑上错了,因为当提示框显示的时候,在提示框弹出前通过SetFocus设置的焦点都将作废

 

发现这一点后,我将弹出提示框前需要设置获得焦点的目标控件存储起来,等提示框显示完了我仍然可以对该控件进行设置焦点的操作,问题总算解决了

 

这里写出来,希望大家不要走我这样的弯路哦!

 

顺便说一下如何获取到焦点所在的控件的ID号,也许这对大家操作焦点所在控件有作用;

MFC::
CWnd *pWnd = GetFocus(); 
if(pWnd == NULL)
;//no focus
else
UINT nID = pWnd->GetDlgCtrlID();

SDK:
HWND hWnd = ::GetFocus();
if(hWnd == NULL)
;//no focus 
else
UINT nID = ::GetDlgCtrlID(hWnd);

转载注明出处哦,谢了!

========================================================================================
mfc解决回车键默认关闭窗口的一般方法
在一般情况下编写的对话框程序,用户在运行的时候,如果不注意按下了ENTER或者ESC键,程序就会立刻退出,之所以会这样,是因为按下Enter键时,Windows就会自动去找输入焦点落在了哪一个按钮上,当获得焦点的按钮的四周将被点线矩形包围。如果所有按钮都没有获得输入焦点,Windows 就会自动去寻找程序或资源所指定的默认按钮(默认按钮边框较粗)如果对话框没有默认按钮,那么即使对话框中没有OK按钮,OnOK函数也会自动被调用,对于一个普通的对话框程序来说,OnOK函数的调用,以为着程序会立刻退出。为了使Enter键无效,最简单的办法就是将CExDlgOnOK函数写成空函数,然后针对OK按钮写一个新的函数来响应。ESC键的原理也是如此,它是默认和OnCancel函数映射在一起的。对于ESC键,需要自己重载 CDialog类的PreTranslateMessage函数,当发现是ESC键的时候,过滤掉这个消息或者是替换掉这个消息。 

一下是简单的代码示例: 

【方法1 
可以先重载OnOK函数 
void CTestDlg::OnOK()
{ //
里面什么也不写}

然后重载PreTranslateMessage函数 
ESC键的消息,用RETURN键的消息替换,这样,按ESC的时候,也会执行刚才的OnOK函数,这样问题就可以解决了。 

BOOL CxxxDlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_ESCAPE)
{
pMsg->wParam=VK_RETURN; //
ESC键的消息替换为回车键的消息,这样,按ESC的时候 
//
也会去调用OnOK函数,而OnOK什么也不做,这样ESC也被屏蔽 

}
return CDialog::PreTranslateMessage(pMsg);

}

【方法2 

直接在重载的PreTranslateMessage函数中屏蔽回车和ESC的消息,和以上方法大同小异: 

BOOL CxxxDlg::PreTranslateMessage(MSG* pMsg)
{
if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_ESCAPE) return TRUE;
if(pMsg->message==WM_KEYDOWN && pMsg->wParam==VK_RETURN) return TRUE;
else
return CDialog::PreTranslateMessage(pMsg);
}
==============================================================================

用回车键实现MFC对话框中TAB键控件输入焦点在控件中跳转的效果

  • 版权声明:转载时请以超链接形式标明文章原始出处和作者信息及本声明
    http://hcq11.blogbus.com/logs/54217707.html

    近日在为一个数据应用写数据输入界面,大量的编辑框要想实现快速的输入就是有设计良好的符合工作流程的TAB键序。相信,不少的人在使用具有大量编辑框的程序时都有这样的想法和感概。而我这个对话框界面主要输入的是数字,因此如果使用TAB键作编辑框之间的跳转会在使用数字键盘时不方便。因此,就考虑了用回车键来实现TAB键的功能。因为MFC对话框的特点,基于MFC对话框的对话框按下回车键会调用框架内的的OnOk成员函数导至退出。即使你去掉IDC_OK按键的BS_DEFPUSHBUTTON 属性也是不行的
    必须重载WM_GETDEFID,因为当用户按下回车键时,Windows发送WM_GETDEFID消息来获得缺省的命令ID,Windows再将它作为WM_COMMAND发送,所以重载这个消息必须在高位字中返回DC_HASDEFID。 如下所例:
[cpp] view plain copy
  1. BEGIN_MESSAGE_MAP(CMyDlg, CDialog)  
  2.     ON_MESSAGE(DM_GETDEFID, OnGetDefID)  
  3.     ...  
  4. END_MESSAGE_MAP()  
  5.   
  6. LRESULT CMyDlg::OnGetDefID(WPARAM wp, LPARAM lp)   
  7. {  
  8.     return MAKELONG(0,DC_HASDEFID);   
  9. }   

  • 这是一种方法,另外一种方法是在消息循环处着手处理。重载PreTranslateMessage这个虚函数,将消息队列中有关键盘按下的消息给拦载下来,在框架之前处理WM_KEYDOWN消息。判断是按下回车键后,我们可以用GetNextDlgTabItem 函数获得TAB键序中下一个或上一个接受TAB键的控件句柄。示例代码如下:

[cpp] view plain copy
  1. BOOL CKeydownDlg::PreTranslateMessage(MSG* pMsg)   
  2. {  
  3.      if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)  
  4.      {  
  5.            CWnd *mwnd = GetNextDlgTabItem (GetFocus());        //取得当前焦点控件的下一个控件的句柄  
  6.            if (mwnd)  
  7.            {  
  8.                 mwnd->SetFocus();        //设置下一件控件得到输入焦点  
  9.                 return TRUE;  
  10.            }  
  11.      }  
  12.    return CDialog::PreTranslateMessage(pMsg);  
  13. }  

  •   但是,各位有没有注意到。这样处理之后,虽然可以在各个控件之进行输入焦点的转移。可是当一个按钮控件获得了焦点之后,也是按下回车键。以前我们习惯中或者说预料中按下该按钮的后应该执行的功能没有被执行,而焦点又跑到按钮之后的控件上去了。这就是上面代码的不足之处,虽然实现了焦点由回车键控件转移,但是按钮却不能用回车键来操作了。只以用鼠标,这和大家习惯不合。而且,在快速的数据输入中不能用回车键来按下这个按钮却要用鼠标来点击也有违当初我们要快速这样一个目的。所以,还得对以上代码做适当的修改。代码如下。
            在这里增加了对当前焦点控件类的判断,即如果当前控件是按钮(Button)那么就不执行焦点跳转而是构造一条WM_COMMAND消息发送给程序,让程序以为是鼠标点击了该按钮。从而执行了这个按钮具有的功能而不是什么也不做的焦点转移。

    [cpp] view plain copy
    1. BOOL CKeydownDlg::PreTranslateMessage(MSG* pMsg)   
    2. {  
    3.       if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)  
    4.       {  
    5.           CWnd *wnd = GetFocus ();  
    6.           if (wnd != NULL)  
    7.           {  
    8.                char str[256];  
    9.                CString ClassName = _T("Button");  
    10.                GetClassName (wnd->m_hWnd, str, 256);  
    11.                  if (ClassName == str)  
    12.                  {  
    13.                         UINT i = wnd->GetDlgCtrlID ();  
    14.                         SendMessage (WM_COMMAND, i, (LPARAM)wnd->m_hWnd);  
    15.                         return TRUE;  
    16.                    }  
    17.          }  
    18.       CWnd *mwnd = GetNextDlgTabItem (wnd);  
    19.       if (mwnd)  
    20.       {  
    21.             mwnd->SetFocus();  
    22.            return TRUE;  
    23.        }  
    24. }  
    25.   
    26. return CDialog::PreTranslateMessage(pMsg);  
    27. }  

    • TAB ORDER按回车键使下个控件自动获得焦点

      1.选中主对话框:Layout菜单=>Tab Order(或者直接按Ctrl+D):按你需要的TAB顺序依次单击控件.

      2.按Ctrl+W打开MFC ClassWizard=>Message Maps选项卡:给你的主DLG映射PreTranslateMessage消息处理函数:

    [cpp] view plain copy
    1. BOOL CYourDlg::PreTranslateMessage(MSG* pMsg)   
    2. {  
    3.     // 顺次传递焦点,除非当前焦点在确定按钮上时才响应触发消息  
    4.     if((pMsg->message == WM_KEYDOWN) && (VK_RETURN == (int) pMsg->wParam))  
    5.     {  
    6.         if(GetFocus()->GetDlgCtrlID() != IDOK)  
    7.         {  
    8.             pMsg->wParam = VK_TAB;  
    9.         }  
    10.     }  
    11.   
    12.     return CDialog::PreTranslateMessage(pMsg);  
    13. }  


三、解决在无窗口的程序中采用MessageBox弹出的对话框具有模态特性

1、MessageBox第一个参数介绍:
hWnd 
[in] Handle to the owner window of the message box to be created. If this parameter is NULL, the message box has no owner window. 
这个hwnd,就给出了meessagebox这个类似或者说就是模态对话框的父窗口,对于模态对话框,楼主应该知道什么意思了吧, 其他窗口将不会拥有焦点,若hwnd == NULL,  has no owner window当然就有其他窗口会得到焦点, 这跟domodel(NULL),一样的道理,就是这个,但是不能说他阻塞了其他线程,没这个说法!


可是我测试了一下,若我第一个参数传::GetDesktopWindow()
发现他和传NULL的效果一样(当然这个效果是指我们表面上看上去的效果)
那这个时候MessageBox是模态还是非模态?模态的话,主窗口就是桌面了吗??
2、解决MessageBox(NULL弹出对话框后,按回车默认不能关闭弹出框的方法:
[cpp] view plain copy
  1. if ( !m_hwndParent )  
  2.     {  
  3.         m_hwndParent = ::GetForegroundWindow();  
  4.     }  
  5.     if ( IDOK != m_fnMessageBox(m_hwndParent, TEXT_CONN_FAILE, CAPTION_DISCONN, MB_OK, MB_ICONERROR|MB_SYSTEMMODAL))  
  6.     {  
  7.         bRet = FALSE;  
  8.     }  
  9.     else  
  10.     {  
  11.         bRet = TRUE;  
  12.     }  


转载自:http://blog.csdn.net/chenyujing1234/article/details/8958322
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:22337次
    • 积分:528
    • 等级:
    • 排名:千里之外
    • 原创:27篇
    • 转载:14篇
    • 译文:0篇
    • 评论:2条
    最新评论