MFC Document/View Architecture: |
|
Introduction |
As you may have found out from the Windows controls we reviewed in previous lessons, the contents of a window may hide some of its parts. To show such parts, the control can be equipped with a scroll bar. This characteristic also applies to a view. Here is an example: |
CView, the parent of all MFC view classes, doesn’t provide a default functionality that allows the user to scroll from one side of a view to another. If you use a CView view and want this functionality, you can implement it yourself, using the appropriate methods of that class. Because scrolling is very important and should be anticipated in many applications, the MFC library provides the CScrollView class.
If you know for sure that the documents of an application you are creating will require scrolling, either vertically, horizontally or both, you should create it based on the CScrollView class. This class provides all the default scrolling functionalities that a view would need. It is equipped to scroll left and right or up and down. There are two main ways you can create a CScrollView-based application. If you are creating an application using the MFC Application wizard, you can select CScrollView as the base class. If you are manually creating your application, derive your view class on CScrollView. CScrollView is based on the CView class where it inherits a good part of its functionality. For example, if you want to draw on a CScrollView object, you can call the use the CView::OnDraw event. This event is automatically generated for you if you use the MFC Application wizard to create your project. If you want to print the contents of a CScrollView object, you can use the event of the CView class as we reviewed them when studying printing. Here is an example of using the OnDraw event of a scroll view as if it were a regular CView object: void CExerciseView::OnDraw(CDC* pDC) { CExerciseDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: add draw code for native data here CBitmap bmpCar; CDC mdcCar; bmpCar.LoadBitmapW(IDB_CAR); mdcCar.CreateCompatibleDC(pDC); CBitmap *bmpOld = mdcCar.SelectObject(&bmpCar); pDC->BitBlt(0, 0, 385, 215, &mdcCar, 0, 0, SRCCOPY); pDC->SelectObject(bmpOld); }
A scroll view is meant to show scroll bars only when necessary. To make this decision, the view should be aware of the dimensions of the document. When you have just created a CScrollView application, the view doesn’t know what dimensions it would use in the scrolling region. This characteristic can be specified using the CScrollView::SetScrollSizes() method. Its syntax is: void SetScrollSizes(int nMapMode, SIZE sizeTotal, const SIZE& sizePage = sizeDefault, const SIZE& sizeLine = sizeDefault); Ths nMapMode argument holds a mapping mode that can be MM_TEXT, MM_HIMETRIC, MM_TWIPS, MM_HIENGLISH, MM_LOMETRIC, or MM_LOENGLISH. The sizeTotal argument is the width and the height values that will be set as the maximum dimensions of the scrolling area. The optional sizePage argument is the value by which the view would be scrolled for a page, that is, when the user clicks inside the scrolling region of the bar. The optional sizeLine argument is the value by which the view would scroll when the user clicks once in one of the arrow buttons of the scroll bar. If you want to specify the default dimensions of the view for your application, you can use the CView::OnInitialUpdate event that the CScrollView class inherits. If you create a CScrollView-based project using the MFC Application, the wizard would generate an OnInitialUpdate event for you and would write a default SetScrollSizes code that, in most cases, you should modify. Using the sizeTotal, you can specify only the width, only the height, or both. As mentioned above, the view doesn’t always show the scroll bars. For example, if the application itself or the user increases the size of the frame so it would be greater than the dimensions stored in the SIZE value of the SetScrollSizes() method, the scroll bars would disappear. Here is an example: BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if( !CFrameWnd::PreCreateWindow(cs) ) return FALSE; // TODO: Modify the Window class or styles here by modifying // the CREATESTRUCT cs cs.cx = 410; cs.cy = 310; cs.style &= ~FWS_ADDTOTITLE; return TRUE; } void CExerciseView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal; // TODO: calculate the total size of this view sizeTotal.cx = 385; sizeTotal.cy = 215; SetScrollSizes(MM_TEXT, sizeTotal); } In the same way, when you pass constant values as the sizeTotal of the SetScrollSizes() method, you should have a good idea of the dimensions of the contents of the view. An alternative is to get the dimensions of the contents and store them in a value. For example, if you are using the view to display a picture, it may be a good idea to know the dimensions of that picture so the view would fit it. To know the current size of the scrolling region and even the mapping mode applied to it, you can call the GetDeviceScrollSizes(). Its syntax is: void GetDeviceScrollSizes(int& nMapMode, SIZE& sizeTotal, SIZE& sizePage, SIZE& sizeLine ) const; At any time, to get the size of the scrolling region, you can call the GetTotalSize() method. Its syntax is: CSize GetTotalSize( ) const; This method returns the width, as a CSize::cx value, and the height, as a CSize::cy value, of the scroll view.
Remember that, depending on the size of the content relative to the frame of the window, the view may or may not display the scroll bar(s). In some cases, before performing an operation on the view or its contents, you may need to know whether the view is currently equipped with one or both scroll bars. To get this information, you can call the CheckScrollBars() method. Its syntax is: void CheckScrollBars(BOOL& bHasHorzBar, BOOL& bHasVertBar) const; Notice that each argument is passed by reference. This means that each would return a value. After calling this method, if the frame is displaying a horizontal scroll bar, the first argument would return with a TRUE value. If the frame is displaying a vertical scroll bar, the second argument would return with a TRUE value.
CPoint GetDeviceScrollPosition( ) const; This method returns the position, as a CPoint coordinate, of the scroll boxes.
Imagine you have specified the contents of the document. For example, suppose you are using the view to display a picture and allow the user to scroll to get to hidden sections. If the user resizes the window to a width longer than the contents, the horizontal scroll bar would disappear. Consider the following example:
In the same way, if the user resizes the window to a height taller than the contents, the vertical scroll bar would disappear. As mentioned already, if the user resizes the whole window wider and taller than the contents, both scroll bars would disappear:
If you want, and if your application is appropriate for it, you can use a stretching effect so that the contents of the document would extend to the resizing dimensions of the view when the user changes the size of the window. Consider the following two screenshots: If you want the contents of the view to resize itself to fit the view when the user resizes the window, instead of calling SetScrollSizes, call the CScrollView::SetScaleToFitsSize() method. Its syntax is: void SetScaleToFitSize(SIZE sizeTotal); The argument specifies the dimensions of the view. After calling this method, the view doesn’t have scroll bars anymore and its contents would assume any size the view gets resized to. Here is an example of calling this method: void CExerciseView::OnInitialUpdate() { CScrollView::OnInitialUpdate(); CSize sizeTotal; // TODO: calculate the total size of this view sizeTotal.cx = 385; sizeTotal.cy = 215; SetScaleToFitSize(sizeTotal); } |
|
||
Home | ||
|