Microsoft KB Archive/134763

{|
 * width="100%"|

PRB: Controls in Toolbars Refuse to Give the Focus to Views

 * }

Q134763

-

The information in this article applies to:


 * The Microsoft Foundation Classes (MFC), included with:
 * Microsoft Visual C++, versions 1.5, 1.51, 1.52

-

SYMPTOMS
In an MFC application, controls added to a toolbar may prevent the input focus from returning to the active view. For example, when a user clicks a combo box or edit control in a toolbar and then clicks a view, the control retains the input focus. This happens for any CControlBar-derived class containing a control that can accept the input focus. This behavior does not exist for views derived from CFormView or CEditView.

CAUSE
When MFC reactivates an already active view, it does not set the input focus to the view. As a result, any control in the toolbar which has the input focus retains the focus.

For Single Document Interface (SDI) applications
To overcome this behavior when you are writing a Single Document Interface (SDI) application, you must handle the case of a mouse click in the client area (the view itself) of the main window. You need to override OnMouseActivate in your CView-derived class. To do this, be sure to add an ON_WM_MOUSEACTIVATE entry to your message map. ClassWizard displays WM_MOUSEACTIVATE in the Messages list if you first choose the Class Info tab and change your Message Filter to "Window." In the code for OnMouseActivate, call the base class implementation first, and save the result. If the result is MA_ACTIVATE or MA_ACTIVATEANDEAT, then call OnActivateView. Return the result you saved from your call to the base class. The following code demonstrates this:

int CMyView::OnMouseActivate(CWnd* pDesktopWnd,       UINT nHitTest, UINT message) {   // Call the base class to get a return value int nResult = CView::OnMouseActivate(pDesktopWnd,           nHitTest, message);

if (nResult == MA_ACTIVATE || nResult == MA_ACTIVATEANDEAT) {        OnActivateView(TRUE, this, this); }

return nResult; }

For Multiple Document Interface (MDI) Applications
If you are writing a Multiple Document Interface (MDI) application, there are two ways a view might be reactivated. You must handle both to overcome the focus behavior.

To handle the case of a mouse click in a non-client part of the MDI child window, override OnMouseActivate in your CMDIChildWnd-derived class. To do this, be sure to add an ON_WM_MOUSEACTIVATE entry to your message map. ClassWizard will display WM_MOUSEACTIVATE in the Messages list if you first choose the Class Info tab and change your Message Filter to "Window." In the code for OnMouseActivate, call the base class implementation first, and save the result. Then call SetFocus, and return the result you saved from your call to the base class. The following code demonstrates this:

int CMyMDIChildWnd::OnMouseActivate(CWnd* pDesktopWnd,       UINT nHitTest, UINT message) {   // Call the base class FIRST to get a return value for later int nResult = CMDIChildWnd::OnMouseActivate(pDesktopWnd,           nHitTest, message);

// Correct for focus not being set in   // CMDIChildWnd::OnMouseActivate SetFocus;

return nResult; } To handle the case of choosing the already-checked item for the MDI child window from the application's Window menu, override OnCommand for your CMainFrame class. Call the base class implementation first, and save the result. Then determine that the menu item ID you are passed is for an MDI child window, that it is your own MDI child, which should be active, and that you are of the runtime class CView. If all of that is true, then call SetFocus, and return the value you saved from your call to the base class. The following code, adapted from the MFC source for CMDIFrameWnd::OnCommand, demonstrates how to do this:

BOOL CMainFrame::OnCommand(WPARAM wParam, LPARAM lParam) {   // Call the base class FIRST to get a return value for later BOOL bRet = CMDIFrameWnd::OnCommand(wParam, lParam);

ASSERT(AFX_IDM_FIRST_MDICHILD == 0xFF00); // If the correct part of lParam is NULL, this message was sent // because a menu item was chosen with the mouse or the keyboard if (LOWORD(lParam) == NULL &&           (LOWORD(wParam) & 0xf000) == 0xf000) {       ASSERT_VALID(MDIGetActive(NULL)); // Do this ONLY for a CView-derived class if ((GetFocus->GetParentFrame != MDIGetActive(NULL)) &&               (MDIGetActive(NULL)->GetActiveView-> IsKindOf(RUNTIME_CLASS(CView)))) {           SetFocus; }   }

return bRet; }

STATUS
This behavior is by design.