在Dialog中button与回车键

在Dialog中button与回车键

 

1,  如果该Dialog中,某个button拥有focus,则敲回车键时会响应该按钮;

注:button拥有focus的方法:

(a)使用Tab键切换到某按钮;

(b)在建立Dialog时设定Tab Order,把某一button的tab顺序设为1,则该Dialog初始时,这个button拥有focus;(打开资源(.rc)文件,可以发现得到焦点的按钮总是在最前面)

(c)但是,如果在程序代码中 用SetFocus()设定某一按钮拥有focus,再敲回车键,该按钮不能被响应,不知为何?!

 

2,  如果该Dialog中,没有任何button拥有focus,但是该Dialog有default button,则敲回车键时会响应该default button;

例如当前的focus在edit控件上,则此时回车 会响应default button。

一般来讲,每个dialog都应该设有一个default button,且该button最好没有伤害性(比如删除、保存操作);

注:所谓Default Button,其表现为,在Dialog中如果focus不在任何按钮上,则Default button 为黑边。

 

3,  如果该Dialog中,没有任何button拥有focus,也没有default button,则敲回车键时:

windows为对话框提供了一个专用的键盘接口,专门用于对几个键进行处理,如:

ENTER键,给对话框发送一条WM_COMMAND消息,参数wParam被设置成IDOK;而ESC键,给对话框发送一条WM_COMMAND的消息,参数wParam被设置成IDCANCEL。所以敲回车时,会响应IDOK的处理函数OnOK(),如果在你的Dialog中没有重载OnOK(),则会调用CDialog::OnOK(),在这个函数中会调用EndDialog函数关闭对话框。

因此如果想使回车键和ESC键都不关闭对话框,则应在你的Dialog中重载OnOK()和OnCancel()函数。如下:(方法一)

void CMyDlg::OnOK()

{

       //CDialog::OnOK();

       return;

}

 

void CMyDlg::OnCancel()

{

       //CDialog::OnCancel();

       return;

}

但是上述方法的缺点时无法用X关闭对话框了(可以不重载OnCancel()),优点是,当focus在某个button上时,按回车键可以响应该button!

 

随着C++和MFC的日臻成熟,现在几乎整个消息循环(但不是全部)都被隐藏到了MFC中,为了能让任何窗口都有机会获得一点消息泵的行为,MFC提供了一个专门的虚函数PreTranslateMessage,如果你有足够的勇气去探究CWinThread中的消息处理机制的话,你会遇到类似如下的代码:

// 简化后的 CWinThread

while (GetMessage(...)) {

    if (PreTranslateMessage(...)) {

        // continue looping

    } else {

        TranslateMessage(...);

        DispatchMessage(...);

    }

}

CWinThread::PreTranslateMessage是个虚函数,在应用中,其缺省的实现以相同的名字调用另一个虚函数,CWnd::PreTranslateMessage。

所以如果想使回车键和ESC键都不关闭对话框,则可以在我们的对话框总重载PreTranslateMessage,如下:(方法二)

BOOL CMyDlg::PreTranslateMessage(MSG* pMsg)

{

       if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST)

       {

              if (pMsg->wParam == VK_RETURN)

              {

                     return TRUE;

              }

              else if (pMsg->wParam == VK_ESCAPE)

              {    

                     return TRUE;

              }

       }

       return CDialog::PreTranslateMessage(pMsg);

}

上述做法的缺点是:回车键彻底无效了,即使某个button拥有focus,按回车也不行去响应他!优点是:可以用X关闭对话框!

 

4,如果想在对话框中使用回车键,比如使得多个Edit控件响应回车键:

首先看一下:

typedef struct tagMSG{

 /*msg*/

 HWND hwnd;//窗口句柄,标识接收消息的窗口。

 UINT message;//消息标识号,如WM_TIMER等。

 WPARAM wParam;//消息参数,当为键盘消息时,表示虚拟键码如VK_RETURN等。

 LPARAM lParam;//消息参数。

 DWORD time;//邮寄消息的时间。

 POINT pt;//邮寄消息时的光标位置,用屏幕坐标表示。

}MSG;

 

  在Windows下的程序中,所有的资源都是有唯一标号的,使每个资源对象能唯一的区别于其他资源,所以我们可以通过资源ID来对编辑框做出区别,使之完成各自的响应处理。在Microsoft Visual C++ 6.0下可以通过"View"菜单的"ID= Resource Symboles…"查到指定ID的资源标识号的实际数值,如在本例中的两个编辑框IDC_EDIT1和IDC_EDIT2所对应的数值分别为1000和1001,对前面的解析消息的代码做些改动,主要如下所示:

BOOL CMyDialog::PreTranslateMessage(MSG* pMsg)

{

 if (WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST)

 {

if(pMsg->wParam==VK_RETURN )

{

     HWND hWnd=::GetFocus();

     int iID=::GetDlgCtrlID(hWnd);

     if(iID==1000)//第一个编辑框的标识为1000

     {

         UpdateData(TRUE);

         AfxMessageBox(m_Text1);//显示第一个编辑框的内容

     }

     if(iID==1001) //第二个编辑框的标识为1001

     {

         UpdateData(TRUE);

         AfxMessageBox(m_Text2);//显示第二个编辑框的内容

     }

}

}

  在此通过API函数::GetFocus()取得当前光标所处的(即有焦点的)编辑框的句柄,然后通过API函数::GetDlgCtrlID()根据这个句柄返回此窗口资源的ID 号,该ID号是动态获取的,使之同预先查看好的编辑框的ID作下比较即可区分出是需要哪个编辑框对回车键作出响应。

 

4,  如何解决 某个对话框中的Child Dialog的按钮拥有focus,但此时回车键不能响应它?

 

问题解释:此时回车,会产生WM_COMMAND消息,参数是当前拥有focus的按钮的ID,但是由于child dialog没有消息循环,所以这个消息被 父dialog截获。可是,父dialog中并没有这个button ID,所以它也无法响应。(如果父dialog中有这个button id, 则在child dialog中回车会响应父dialog中相同id的button!!)因此,我们要做的是在父dialog无法处理这个消息的时候,将其返回给child dialog 处理。

示例:

BOOL CParentDialog::OnCmdMsg(UINT nID, int nCode, void* pExtra, AFX_CMDHANDLERINFO* pHandlerInfo)

{

       /*When the focus is on a button of child dialog, click [enter] key, and then the message will go here(Parent dialog)!But the parent dialog doesn't have this nID, so OnCmdMsg will return false.In this condition, we just return it to the child dialog to deal with it...*/

       if (!CParentParentDialog::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))

       {

              if (m_dlgchild1.IsWindowEnabled())

              {

                     return m_ dlgchild1.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);      

              }

              else if (m_ dlgchild2.IsWindowEnabled())

              {

                     return m_ dlgchild2.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

              }

              else if (m_ dlgchild2.IsWindowEnabled())

              {

                     return m_ dlgchild2.OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);

              }

              else

               return FALSE;

       }

       return TRUE;

}

您可以在Dialog的EditText设置一个OnEditorActionListener,然后在监听器捕获IME_ACTION_DONE事件。当用户点击键盘上的回车键时,该事件会被触发。您可以在该事件的回调方法调用Dialog的onPositiveButtonClick方法,这样就可以触发Dialog的确定按钮事件并执行所需的操作。下面是一个示例代码: ``` AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("Dialog Title"); final EditText editText = new EditText(this); editText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_DONE) { // 触发Dialog的确定按钮事件 dialog.getButton(DialogInterface.BUTTON_POSITIVE).performClick(); return true; } return false; } }); builder.setView(editText); builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { // 执行你需要的操作 String text = editText.getText().toString(); Toast.makeText(MainActivity.this, "Text: " + text, Toast.LENGTH_SHORT).show(); } }); builder.setNegativeButton("Cancel", null); AlertDialog dialog = builder.create(); dialog.show(); ``` 在上面的代码,我们在Dialog的EditText设置了一个OnEditorActionListener,并在回调方法调用了Dialog的onPositiveButtonClick方法。在Dialog的确定按钮事件,我们可以像平常一样执行我们需要的操作。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值