Microsoft Developer Network >
Forenhomepage
>
Visual C++ General
>
My CButton class does not respond to ENTER key.
My CButton class does not respond to ENTER key.
- Hi all,
I have a custom button class that is derived from MFC CButton class. This class is owner drawn (Overriding DrawItem()). The button draws correctly, responds to mouse clicks correctly and I can TAB to it correctly as well. When in focus, the button gets activated by pressing the space bar. However, for some reason, the when the button is in focus, it does not respond/get activated when the ENTER key is pressed. I replaced my button with the MFC CButton class and it responds to ENTER key just fine when focused.
So, does subclassing the CButton class mean I have to handle the OnGetDlgCode()/OnKeyDown()/OnChar() functions to handle the ENTER key now? Is that the case for any control that is subclassed? What am I missing here? Thanks for your help.
P.S. I had forgotten to mention that my button is not the default button in the dialog.
Antworten
- I finally figured it out. Here is my solution:
In my custom (owner-drawn, non-default) button class (subclassed CButton class), I am intercepting the ENTER key and sending a BN_CLICKED notification code to the parent dialog via the WM_COMMAND message. The code is as follows:
void IconButton::OnKeyDown(UINT nChar, UINT nPreCnt, UINT nFlags)
{
if (nChar == VK_RETURN ||
nChar == VK_SPACE ||
nChar == VK_TAB)
{
// Handle this in OnChar()
return ;
}
return CButton::OnKeyDown(nChar, nPreCnt, nFlags);
}
void IconButton::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch (nChar)
{
case VK_RETURN:
case VK_SPACE:
// Handle the ENTER and SPACEBAR keys.
GetParent()->SendMessage(
WM_COMMAND,
MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED),
(LPARAM) GetSafeHwnd());
break;
case VK_TAB:
GetParent()->SendMessage(WM_NEXTDLGCTL, 0, 0);
break;
default:
// Handle the rest.
CButton::OnChar(nChar, nRepCnt, nFlags);
}
return ;
}
UINT IconButton::OnGetDlgCode()
{
// Intercept all keyboard inputs. We don't get the option to just intercept the ENTER key. Thus,
// in OnChar/OnKeyDown we are forced to handle all keyboard inputs that are relevant to the button.
return CButton::OnGetDlgCode() | DLGC_WANTMESSAGE;
}
In my dialog class, I added the ON_BN_CLICKED to the map entry to handle the button click:
BEGIN_MESSAGE_MAP
ON_BN_CLICKED(myButtonID, myButtonClicked)
END_MESSAGE_MAP
I already had the myButtonClicked function previously for mouse clicks, etc. But it also now works when the user presses ENTER on my button (when it is in focus) or the SPACEBAR. Hope this helps.
Any further comments, opinions are welcome. Thanks.
- Als Antwort markiertfkhanoom Donnerstag, 5. November 2009 01:11
Alle Antworten
- Set default button property true or modify button style to BS_DEFPUSHBUTTON
or try CDialog::SetDefID function
Kind Regards
Manoj Jangid
मनोज कुमार जांगिड NATHCORP - This is one of the mysteries of ::IsDialogMessage(). If VK_RETURN is pressed normal buttons get special treatment. But buttons with the BS_OWNERDRAW style do not. You can exclude VK_RETURN from beeing handled by ::IsDialogMessage() and handle that key your self this way:
BOOL CYourDialog::PreTranslateMessage(MSG* pMsg)
{
switch ( pMsg->message )
{
case WM_KEYDOWN:
{
switch( pMsg->wParam )
{
case VK_RETURN:
::DispatchMessage( pMsg );
return true;
}
break;
}
}
return CDialog::PreTranslateMessage(pMsg);
}
- I would like my button class to be reusable. Therefore, I rather handle it in the subclassed button class rather than in my dialog(s). In that case, I should probably override OnGetDlgCode()/OnKeyDown()/OnChar() functions in my button class to handle the ENTER key.
- Your button is located on dialog?
- Yes it's located on a dialog.
Have you seen this thread?
- Hi Nikita,
I saw the question in that thread but you have to pay/provide some info to get the answer. If you have access to the thread answer, could you post it here?
I tried the previous two solutions provided here and they did not work.
I did find an article that explains what to do to make an owner drawn button to behave correctly, mind you it's a lengthy process and I am yet to try it: http://www.codeproject.com/KB/buttons/oddbutton.aspx?msg=80296. - You just need to scroll site to the bottom and you will see answers. It's EE site trick =)
- Also, I think that codeproject article is the best solution for your problem, IMHO
- I am not sure if the codeproject article handles a non-default owner-drawn button case. I should have mentioned in my problem description that my button is not the dialog's default button.
- Yes, it uses default button technique.Also, I've tested sample from code project article and it works incorrectly =)
- I better use Spy++ to see what the difference between a standard and owner-drawn button message map is. I don't see any other way :(
- I finally figured it out. Here is my solution:
In my custom (owner-drawn, non-default) button class (subclassed CButton class), I am intercepting the ENTER key and sending a BN_CLICKED notification code to the parent dialog via the WM_COMMAND message. The code is as follows:
void IconButton::OnKeyDown(UINT nChar, UINT nPreCnt, UINT nFlags)
{
if (nChar == VK_RETURN ||
nChar == VK_SPACE ||
nChar == VK_TAB)
{
// Handle this in OnChar()
return ;
}
return CButton::OnKeyDown(nChar, nPreCnt, nFlags);
}
void IconButton::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
switch (nChar)
{
case VK_RETURN:
case VK_SPACE:
// Handle the ENTER and SPACEBAR keys.
GetParent()->SendMessage(
WM_COMMAND,
MAKEWPARAM(GetDlgCtrlID(), BN_CLICKED),
(LPARAM) GetSafeHwnd());
break;
case VK_TAB:
GetParent()->SendMessage(WM_NEXTDLGCTL, 0, 0);
break;
default:
// Handle the rest.
CButton::OnChar(nChar, nRepCnt, nFlags);
}
return ;
}
UINT IconButton::OnGetDlgCode()
{
// Intercept all keyboard inputs. We don't get the option to just intercept the ENTER key. Thus,
// in OnChar/OnKeyDown we are forced to handle all keyboard inputs that are relevant to the button.
return CButton::OnGetDlgCode() | DLGC_WANTMESSAGE;
}
In my dialog class, I added the ON_BN_CLICKED to the map entry to handle the button click:
BEGIN_MESSAGE_MAP
ON_BN_CLICKED(myButtonID, myButtonClicked)
END_MESSAGE_MAP
I already had the myButtonClicked function previously for mouse clicks, etc. But it also now works when the user presses ENTER on my button (when it is in focus) or the SPACEBAR. Hope this helps.
Any further comments, opinions are welcome. Thanks.
- Als Antwort markiertfkhanoom Donnerstag, 5. November 2009 01:11

