Link to home
Start Free TrialLog in
Avatar of natedog977
natedog977

asked on

Set focus to a second control in a CFormView using Tab key and PreTranslateMessage()

Hi all - This should be a fairly simple question for any veteran MFC coders out there...

I can't figure out how to set the focus to the next control using the tab key? I already have all the code necessary to perform this task working EXCEPT for setting the focus.

I am using MyCFormView::PreTranslateMessage() to capture a WM_KEYDOWN message, then checking for VK_TAB in the pMsg->wParam member.

See me code below...Why isn't the focus going to the appropriate control in the switch statements?

P.S. Additional points will be awarded if you can tell me a better way to catch the shift+tab keypress to set the focus to the previous (vs. next) control.

BOOL MyCFormView::PreTranslateMessage(MSG* pMsg)
{
  if (pMsg->message == WM_KEYDOWN){
    if( pMsg->wParam == VK_TAB ){
      if(m_lastCharVal == 16){ //Shift+Tab was entered - Tab backwards
      AfxMessageBox("BACKWARD");
        switch(m_activeCtrl){
          case 1:
            m_loginout.SetFocus();
            m_activeCtrl = 3;
            break;
          case 2:
            m_usr.SetFocus();
            m_activeCtrl = 1;
            break;
          case 3:
            m_pas.SetFocus();
            m_activeCtrl = 2;
            break;
        }
      }
      else{ //Tab Forward
        AfxMessageBox("FORWARD");
          switch(m_activeCtrl){
            case 1:
              m_pas.SetFocus();
              m_activeCtrl = 2;
              break;
            case 2:
              m_loginout.SetFocus();
              m_activeCtrl = 3;
              break;
            case 3:
              m_usr.SetFocus();
              m_activeCtrl = 1;
              break;
          }
        }
      }
      if(pMsg->wParam == VK_RETURN){
        AfxMessageBox("RETURN");
          Loginout();
      }
      m_lastCharVal = pMsg->wParam;
    }

    return CFormView::PreTranslateMessage(pMsg);
}
Avatar of Priyesh
Priyesh

Try GoToDlgCtrl() instead of setfocus?

Also, doesn't tab and shift+tab work for your formview application by default?

Regards,
Priyesh
Avatar of natedog977

ASKER

Hi Privesh,

See below my responses.

[Try GoToDlgCtrl() instead of setfocus?]
GotoDlgCtrl belongs to CDialog, not CFormView. It cannot be called from CMyFormView::PreTranslateMessage().

When I try...

     GotoDlgCtrl(CWnd::GetDlgItem(IDD_USRID));

...I get this error message...

     error C2065: 'GotoDlgCtrl' : undeclared identifier

[Also, doesn't tab and shift+tab work for your formview application by default?]
Tab and shift+tab work inside all of my CDialog derived classes, but not in my main CFormView class?

Perhaps a few more details would be helpful:
What I am trying to do with the application is allow the user to log in from the main start-up window by entering in values into two User ID and Password CEdit Boxes, then clicking a CStatic text (loaded with a "Logon" bitmap).
The CStatic text and the CEdit boxes are declared as member variables and created in OnInitialUpdate() (maybe this is why I can't tab). The controls were created in OnInitialUpdate() because I wanted the ability to reposition them when the main Window is resized.
sorry for GotoDlgCtrl, it is a member of CDialog.

I remember having formviews with dialog controls on it without no problem with tab. i don't think they were created using Create calls. You can still use MoveWindow to move the controls in OnInitialUpdate(). I mean if you place the controls on your form dialog using the resource editor, and use GetDlgItem(IDC_CONTROL)->MoveWindow() in your oninitialupdate, it should still work and give you the tab keys too.


 
  return CFormView::PreTranslateMessage(pMsg);

 Don't call this if you set the focus yourself, might be reseting the focus for you.
ASKER CERTIFIED SOLUTION
Avatar of Vinayak Kumbar
Vinayak Kumbar

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi,

Sorry for few wrong comments in my code... simply ignored I think, here is correct version

BOOL CMyFormView::PreTranslateMessage(MSG* pMsg)
{
     if((pMsg->message == WM_KEYDOWN) && (pMsg->wParam == VK_TAB))
     {
          // Is Shift pressed??
          if(GetKeyState(VK_SHIFT) & 0x8000)
          {
               // We should be moving backward
               if(m_ctrlBtn.GetSafeHwnd() == pMsg->hwnd)
               {
                    // Focus is on button, move back to check box
                    m_ctrlChk.SetFocus();
                    return TRUE;
               }
               else if(m_ctrlEdit.GetSafeHwnd() == pMsg->hwnd)
               {
                    // Focus is on edit box, move back to button
                    m_ctrlBtn.SetFocus();
                    return TRUE;
               }
               if(m_ctrlChk.GetSafeHwnd() == pMsg->hwnd)
               {
                    // Focus is on check box, move back to edit box
                    m_ctrlEdit.SetFocus();
                    return TRUE;
               }
          }
          else
          {
               // We should be moving forward
               if(m_ctrlBtn.GetSafeHwnd() == pMsg->hwnd)
               {
                    // Focus is on button, move to edit box
                    m_ctrlEdit.SetFocus();
                    return TRUE;
               }
               else if(m_ctrlEdit.GetSafeHwnd() == pMsg->hwnd)
               {
                    // Focus is on edit, move to check box
                    m_ctrlChk.SetFocus();
                    return TRUE;
               }
               if(m_ctrlChk.GetSafeHwnd() == pMsg->hwnd)
               {
                    // Focus is on check box, move to button
                    m_ctrlBtn.SetFocus();
                    return TRUE;
               }
          }
     }

     return CFormView::PreTranslateMessage(pMsg);
}

Hope it helps u.
VinExpert
You don't have to dynamically create controls to be able to move them when the window size changes. Create them in your form view's dialog template from the dialog editor. Then, when you want to move them when the window size changes, map the formview's WM_SIZE and do this. You have to be sure that the OnInitialUpdate was called before you try to access controls in your OnSize(), do this with a boolean variable like

bool m_bDone = false ;
void CFormtestView::OnInitialUpdate()
{
     CFormView::OnInitialUpdate();
     GetParentFrame()->RecalcLayout();
     ResizeParentToFit();

     m_bDone = true ;
}

void CFormtestView::MoveControls(int nCX, int nCY)
{
     GetDlgItem(IDC_EDIT1)->MoveWindow(10, 10, nCX/10, 20) ;
     GetDlgItem(IDC_EDIT2)->MoveWindow(10, 40, nCX/10, 20) ;
}

void CFormtestView::OnSize(UINT nType, int cx, int cy)
{
     CFormView::OnSize(nType, cx, cy);
     if(m_bDone)
          MoveControls(cx, cy) ;    
}

m_bDone will make sure that you move the controls only after  they are created.

Regards,
Priyesh
Thank you all so much for your efforts. I have decided to award VinExpert the points. Each of you had helpfull suggestions. Here is my reasoning...

[] williamcampbell []
You were right about the return value blocking the focus from being set, but after I made the change I was getting an alert beep each time I hit the Tab key?

[] Priyesh []
When I tried using the resource editor to create the controls, I experienced some strange behaviors: On start-up and during resizing the User ID and Password edit controls did not display untill after I hit a key? I realize this is probably because of my own code, but see VinExpert comment below for details on my decision.

[] VinExpert []
I awarded you the points because your comments were correct and your suggestions were the closest to the original code that I provided, meaning less work for me!