FIX: CSplitterWnd Class Does Not Handle All Focus Cases (108434)



The information in this article applies to:

  • The Microsoft Foundation Classes (MFC), when used with:
    • Microsoft Visual C++ for Windows, 16-bit edition 1.0
    • Microsoft Visual C++, 32-bit Editions 1.0

This article was previously published under Q108434

SYMPTOMS

A view displayed in a splitter window (CSplitterWnd) loses focus when the splitter bar is clicked. A user would expect the focus to be returned to the active view when the user stops dragging the splitter bar and releases the mouse button.

CAUSE

CSplitterWnd::StopTracking() attempts to restore the active view's keyboard focus by calling SetActiveView(pOldActiveView), where pOldActiveView was set to the currently active view on entry to the StopTracking() function. This is supposed to set the keyboard focus to the previously active view.

The problem is that SetActiveView() fails to set the keyboard focus in the case where the view passed as a parameter is the same as m_pViewActive--the currently active view. In this case, it is assumed that the keyboard focus is already on the active view, and therefore the SetActiveView() function simply returns. This assumption is incorrect because the splitter bar gains focus, doesn't save and restore it, and yet leaves the frame's active view pointer the same.

RESOLUTION

Microsoft has confirmed this to be a problem in the Microsoft Foundation Class (MFC) Libraries version 2.0. This problem has been fixed in the MFC Libraries version 2.5, which is included in Visual C++ version 1.5 for Windows. In the fixed code, CSplitterWnd::StopTracking() (in WINSPLIT.CPP) is modified to explicitly set the focus even after calling SetActiveView(). The code is:
   if (pOldActiveView == pParent->GetActiveView())
      {
          pParent->SetActiveView(pOldActiveView); // Re-activate.
          if (pOldActiveView != NULL)
              pOldActiveView->SetFocus(); // Make sure focus is restored.
      }
				
You can include this fix into WINSPLIT.CPP and then rebuild the MFC library by following the directions in Appendix B of the "Class Libraries User's Guide" as well as the README.TXT file located in the \MSVC\MFC\SRC directory.

Another workaround for the bug is to save and restore the keyboard focus throughout the splitter window's tracking process. This can be done by handling the WM_LBUTTONDOWN and WM_LBUTTONUP messages in the CSplitterWnd class. The following code demonstrates how to accomplish this:
   class CMySplit:public CSplitterWnd    // derive from it.
   {
       public:
       // This is the pointer to the window that
       // has focus when the splitter starts resizing.
       HWND hWndFocus;

       // ...rest of your declaration.
   }

   void CMySplit::OnLButtonDown(UINT nFlags, CPoint point)
   {
       //Get CWnd with current focus
       hWndFocus = ::GetFocus();

       // Remember to call the base class handler.
       CSplitterWnd::OnLButtonDown(nFlags,point);
   }

   void CMySplit::OnLButtonUp(UINT nFlags, CPoint point)
   {
       //restore focus
       ::SetFocus(hWndFocus);

       // Remember to call the base class handler.
       CSplitterWnd::OnLButtonUp(nFlags,point);
   }
				
The code above assumes that the focus is being set to one of the windows in the splitter window panes before the OnLButtonDown() handler is called. That is, you probably wouldn't want to set the focus back to some other window outside of the splitter window when the mouse button is released. You could write additional code to check to see if the focus is set to a window in one of the panes by checking the splitter's frame window's m_pActiveView variable.

STATUS

This problem has been reported in Visual C++ version 1.0 for Windows. This problem has been fixed in Visual C++ version 1.5 for Windows and Visual C++ 2.0 32-bit Edition.

MORE INFORMATION

To demonstrate the problem, perform the following steps:

  1. Create an App Wizard generated application.
  2. Create a CSplitterWnd in a frame window with two panes that contain CEditView objects.
  3. Build the application and run it.
  4. Click the mouse in the first pane of the splitter window so that the keyboard focus is assigned to that pane; you'll see the caret blink there.
  5. Move the splitter bar to resize the panes.
  6. Observe that the keyboard focus is no longer on the CEditView that you clicked previously.

Modification Type:MajorLast Reviewed:11/18/2003
Keywords:kbbug kbfix KbUIDesign KB108434