Le réseau pour les développeurs > Forums - Accueil > Visual C++ General > My CButton class does not respond to ENTER key.
Poser une questionPoser une question
 

TraitéeMy CButton class does not respond to ENTER key.

  • mardi 3 novembre 2009 23:21fkhanoom Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    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.



    • Modifiéfkhanoom mercredi 4 novembre 2009 00:38Clarify further
    • Modifiéfkhanoom mercredi 4 novembre 2009 20:03Clarify further
    •  

Réponses

  • jeudi 5 novembre 2009 01:11fkhanoom Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     Traitée
    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.



    • Marqué comme réponsefkhanoom jeudi 5 novembre 2009 01:11
    •  

Toutes les réponses

  • mercredi 4 novembre 2009 04:57Jangid Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    Set default button property true or modify button style to BS_DEFPUSHBUTTON

    or try CDialog::SetDefID function

    Kind Regards
    Manoj Jangid

    मनोज कुमार जांगिड NATHCORP
    • Proposé comme réponseJangid mercredi 4 novembre 2009 04:57
    • Non proposé comme réponsefkhanoom jeudi 5 novembre 2009 01:13
    •  
  • mercredi 4 novembre 2009 10:02hgn Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    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);
    }
     

  • mercredi 4 novembre 2009 17:18fkhanoom Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    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.
  • mercredi 4 novembre 2009 17:46Nikita Leontiev Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    Your button is located on dialog?
  • mercredi 4 novembre 2009 17:53fkhanoom Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    Yes it's located on a dialog.
  • mercredi 4 novembre 2009 18:07Nikita Leontiev Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     

    Have you seen this thread?

  • mercredi 4 novembre 2009 18:20fkhanoom Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    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.
  • mercredi 4 novembre 2009 18:33Nikita Leontiev Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    You just need to scroll site to the bottom and you will see answers. It's EE site trick =)
  • mercredi 4 novembre 2009 18:35Nikita Leontiev Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    Also, I think that codeproject article is the best solution for your problem, IMHO
  • mercredi 4 novembre 2009 20:01fkhanoom Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    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.
  • mercredi 4 novembre 2009 20:18Nikita Leontiev Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    Yes, it uses default button technique.
    Also, I've tested sample from code project article and it works incorrectly =)
  • mercredi 4 novembre 2009 20:48fkhanoom Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     
    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 :(
  • jeudi 5 novembre 2009 01:11fkhanoom Médailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateurMédailles de l'utilisateur
     Traitée
    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.



    • Marqué comme réponsefkhanoom jeudi 5 novembre 2009 01:11
    •