How To Scroll a CFormView to See the Controls

Last reviewed: July 31, 1997
Article ID: Q155918
4.00 4.10 4.20 WINDOWS NT kbusage kbprg kbcode kbhowto

The information in this article applies to:

  • The Microsoft Foundation Classes (MFC), included with: Microsoft Visual C++, 32-bit Edition, versions 4.0, 4.1, 4.2

SUMMARY

When a CFormView is resized to something smaller than the size of the dialog box template that it contains and users need to manipulate a control that is not in the visible view area, they must use the scroll bars to get the control into the visible area. This sample code demonstrates how to scroll the CFormView automatically if users tab to a control that is not in view.

MORE INFORMATION

The code sample below works with a CFormView-derived class that contains a dialog box template with more than one control in it (typically an edit control). To see its effect, you must resize the view so that at least one of the controls is not in the current visible client area, then press the TAB key to change focus to that control.

This code works by handling WM_CTLCOLOR messages, checking to see if the control being draw has focus, and scrolling the CFormView to make sure it is visible. WM_CTLCOLOR messages are sent by most controls to their parent before they redraw themselves. The WM_CTLCOLOR message is used instead of the obvious choice, WM_SETFOCUS, because it is sent to the CFormView, not to the actual control. Using WM_SETFOCUS requires subclassing each control.

Sample Code

/* Compile options needed: none
   The class 'CScrollFormView' is derived from CFormView
*/

HBRUSH CScrollFormView::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor) {
   HBRUSH hbr = CFormView::OnCtlColor(pDC, pWnd, nCtlColor);

   if (GetFocus()->m_hWnd == pWnd->m_hWnd)
   {
      CRect rcChild, rcParent, rcTemp;

      pWnd->GetWindowRect(&rcChild);
      GetWindowRect(&rcParent);


     //Get document size. Assume mapping mode is MM_TEXT and ViewPort
     //and Window origins have not been set so we can also assume LP==DP.
      CSize size = GetTotalSize();

      // Determine if scroll bars are visible
      // and subtract their size from the view.
      if (size.cx > rcParent.right - rcParent.left)
         rcParent.bottom -= GetSystemMetrics(SM_CYHSCROLL);
      if (size.cy > rcParent.bottom - rcParent.top)
         rcParent.right -= GetSystemMetrics(SM_CXVSCROLL);

      // Succeed only if no part of the child appears in the parent.
      rcTemp.IntersectRect(rcChild, rcParent);

      if (rcTemp != rcChild)
      {
         POINT pt;

         pt.x = GetDeviceScrollPosition().x;
         pt.y = GetDeviceScrollPosition().y;

         if (rcChild.top < rcParent.top)
         {
            TRACE("control is above the client area\n");
            pt.y -= rcParent.top - rcChild.top +
               GetSystemMetrics(SM_CXEDGE);
         }
         else if (rcChild.bottom > rcParent.bottom)
         {
            TRACE("control is below the client area\n");
            // If the control is taller than the current view
            // scroll up, sacrificing the bottom of the control.
            pt.y += min(rcChild.top - rcParent.top,
               rcChild.bottom - rcParent.bottom +
               GetSystemMetrics(SM_CYHSCROLL) +
               GetSystemMetrics(SM_CXEDGE));
         }

         if (rcChild.left < rcParent.left)
         {
            TRACE("control is left of the client area\n");
            pt.x -= rcParent.left - rcChild.left +
               GetSystemMetrics(SM_CYEDGE);
         }
         else if (rcChild.right > rcParent.right)
         {
            TRACE("control is right of the client area\n");
            // If the control is wider than the current view
            // scroll right, sacrificing the right edge of the control.
            pt.x += min(rcChild.left - rcParent.left,
               rcChild.right - rcParent.right +
               GetSystemMetrics(SM_CXVSCROLL) +
               GetSystemMetrics(SM_CYEDGE));
         }

         ScrollToPosition(pt);  //Assume mapping mode is MM_TEXT.
      }
   }

   // TODO: Return a different brush if the default is not desired.
   return hbr;
}


KBCategory: kbusage kbprg kbcode kbhowto
KBSubcategory: MfcDocView
Additional reference words: 4.00 4.10 4.20 kbdsi
Keywords : MfcDocView kbcode kbhowto kbprg kbusage
Technology : kbMfc
Version : 4.00 4.10 4.20
Platform : NT WINDOWS


THE INFORMATION PROVIDED IN THE MICROSOFT KNOWLEDGE BASE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND. MICROSOFT DISCLAIMS ALL WARRANTIES, EITHER EXPRESS OR IMPLIED, INCLUDING THE WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL MICROSOFT CORPORATION OR ITS SUPPLIERS BE LIABLE FOR ANY DAMAGES WHATSOEVER INCLUDING DIRECT, INDIRECT, INCIDENTAL, CONSEQUENTIAL, LOSS OF BUSINESS PROFITS OR SPECIAL DAMAGES, EVEN IF MICROSOFT CORPORATION OR ITS SUPPLIERS HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. SOME STATES DO NOT ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR CONSEQUENTIAL OR INCIDENTAL DAMAGES SO THE FOREGOING LIMITATION MAY NOT APPLY.

Last reviewed: July 31, 1997
© 1998 Microsoft Corporation. All rights reserved. Terms of Use.