| Tenouk C & C++ | MFC Home | Printing & Print Preview 2 | Splitter Windows & Multiple Views 2 | Download | Site Index |


 

 

 

 

 

 

 

Module 14:

Splitter Windows and Multiple Views 1

 

 

 

 

 

 

 

Program examples compiled using Visual C++ 6.0 (MFC 6.0) compiler on Windows XP Pro machine with Service Pack 2. Topics and sub topics for this Tutorial are listed below:

  1. Splitter Windows and Multiple Views

  2. The Splitter Window

  3. View Options

  4. Dynamic and Static Splitter Windows

  5. The MYMFC21 Example:  A Single View Class SDI Dynamic Splitter

  6. Resources for Splitting

  7. CMainFrame Class

  8. The MYMFC20 steps

  9. Testing the MYMFC21 Application

 

 

 

Splitter Windows and Multiple Views

 

Except for the MYMFC18 example, each program you've seen so far in this book has had only one view attached to a document. If you've used a Microsoft Windows-based word processor, you know that it's convenient to have two windows open simultaneously on various parts of a document. Both windows might contain normal views, or one window might contain a page layout view and another might contain an outline view.

With the application framework, you can use a splitter window or multiple MDI child windows to display multiple views. You'll learn about both presentation options here, and you'll see that it's easy to make multiple view objects of the same view class (the normal view) in both cases. It's slightly more difficult, however, to use two or more view classes in the same application (say, the outline view and the page layout view).

This module emphasizes the selection and presentation of multiple views. The examples depend on a document with data initialized in the OnNewDocument() function. Look back now to Module 10 for a review of document-view communication.

 

The Splitter Window

 

A splitter window appears as a special type of frame window that holds several views in panes. The application can split the window on creation, or the user can split the window by choosing a menu command or by dragging a splitter box on the window's scroll bar. After the window has been split, the user can move the splitter bars with the mouse to adjust the relative sizes of the panes. Splitter windows can be used in both SDI and MDI applications. You can see examples of splitter windows in this module.

An object of class CSplitterWnd represents the splitter window. As far as Windows is concerned, a CSplitterWnd object is an actual window that fully occupies the frame window (CFrameWnd or CMDIChildWnd) client area. The view windows occupy the splitter window pane areas. The splitter window does not take part in the command dispatch mechanism. The active view window (in a splitter pane) is connected directly to its frame window.

 

View Options

 

When you combine multiview presentation methods with application models, you get a number of permutations. Here are some of them:

  • SDI application with splitter window, single view class. This module's first example, MYMFC21, covers this case. Each splitter window pane can be scrolled to a different part of the document. The programmer determines the maximum number of horizontal and vertical panes; the user makes the split at runtime.

  • SDI application with splitter window, multiple view classes. The MYMFC21B example illustrates this case. The programmer determines the number of panes and the sequence of views; the user can change the pane size at runtime.

  • SDI application with no splitter windows, multiple view classes. The MYMFC21C example illustrates this case. The user switches view classes by making a selection from a menu.

  • MDI application with no splitter windows, single view class. This is the standard MDI application you've seen already in Module 12. The New Window menu item lets the user open a new child window for a document that's open already.

Dynamic and Static Splitter Windows

 

A dynamic splitter window allows the user to split the window at any time by choosing a menu item or by dragging a splitter box located on the scroll bar. The panes in a dynamic splitter window generally use the same view class. The top left pane is initialized to a particular view when the splitter window is created. In a dynamic splitter window, scroll bars are shared among the views. In a window with a single horizontal split, for example, the bottom scroll bar controls both views. A dynamic splitter application starts with a single view object. When the user splits the frame, other view objects are constructed. When the user un-splits the frame, view objects are destroyed.

The panes of a static splitter window are defined when the window is first created and they cannot be changed. The user can move the bars but cannot un-split or re-split the window. Static splitter windows can accommodate multiple view classes, with the configuration set at creation time. In a static splitter window, each pane has separate scroll bars. In a static splitter window application, all view objects are constructed when the frame is constructed and they are all destroyed when the frame is destroyed.

 

The MYMFC21 Example:  A Single View Class SDI Dynamic Splitter

 

In this example, the user can dynamically split the view into four panes with four separate view objects, all managed by a single view class. We'll use the document and the view code from MYMFC19. AppWizard lets you add a dynamic splitter window to a new application. Create an SDI project. Click the Advanced button in the AppWizard Step 4 dialog. Click on the Window Styles tab, and select Use Split Window as shown here.

 

MYMFC21 step 4 of 6 AppWizard, the Advanced options settings.

 

Figure 1: MYMFC21 step 4 of 6 AppWizard, the Advanced options settings.

 

MYMFC21 step 6 of 6 AppWizard, using CScrollView for the view base class.

 

Figure 2: MYMFC21 step 6 of 6 AppWizard, using CScrollView for the view base class.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

MYMFC21 project summary.

 

Figure 3: MYMFC21 project summary.

 

When you check the Use Split Window check box, AppWizard adds code to your CMainFrame class. Of course, you could add the same code to the CMainFrame class of an existing application to add splitter capability.

 

Resources for Splitting

 

Build and run MYMFC21 program. When AppWizard generates an application with a splitter frame, it includes a Split option in the project's View menu when you build and run the program. The ID_WINDOW_SPLIT command ID is mapped in the CView class within the MFC library.

 

MYMFC21 program output without any coding.

 

Figure 4: MYMFC21 program output with split windows without any coding.

 

CMainFrame Class

 

The application's main frame window class needs a splitter window data member and a prototype for an overridden OnCreateClient() function. Here are the additions that AppWizard makes to the MainFrm.h file:

 

protected:

    CSplitterWnd m_wndSplitter;

 

public:

    virtual BOOL OnCreateClient(LPCREATESTRUCT  lpcs, CCreateContext*  pContext);

 

Visual C++ code segment

 

Listing 1.

 

The application framework calls the CFrameWnd::OnCreateClient virtual member function when the frame object is created. The base class version creates a single view window as specified by the document template. The AppWizard-generated OnCreateClient() override shown here (in MainFrm.cpp) creates a splitter window instead, and the splitter window creates the first view:

 

BOOL CMainFrame::OnCreateClient( LPCREATESTRUCT /*lpcs*/,

    CCreateContext* pContext)

{

    return m_wndSplitter.Create( this,

        2, 2,           // TODO: adjust the number of rows, columns

        CSize(10, 10),  // TODO: adjust the minimum pane size

        pContext);

}

 

Visual C++ code segment

 

Listing 2.

 

The CSplitterWnd Create() member function creates a dynamic splitter window, and the CSplitterWnd object knows the view class because its name is embedded in the CCreateContext structure that's passed as a parameter to Create(). The second and third Create() parameters (2, 2) specify that the window can be split into a maximum of two rows and two columns. If you changed the parameters to (2, 1), you would allow only a single horizontal split. The parameters (1, 2) allow only a single vertical split. The CSize parameter specifies the minimum pane size.

 

The MYMFC20 steps

 

Before we see the action, let put in the MYMFC20 steps in this example. Add a CStringArray data member to the CMymfc21Doc class. Edit the Mymfc21Doc.h header file or use ClassView.

 

public:

    CStringArray  m_stringArray;

 

Adding member variable to CMymfc21Doc class using ClassView.

 

Figure 5: Adding member variable to CMymfc21Doc class using ClassView.

 

 

Entering the member variable’s type and name.

 

Figure 6: Entering the member variable’s type and name.

 

Visual C++ code segment

 

Listing 3.

 

The document data is stored in a string array. The MFC library CStringArray class holds an array of CString objects, accessible by a zero-based subscript. You need not set a maximum dimension in the declaration because the array is dynamic.

Add a CRect data member to the CStringView class. Edit the StringView.h header file or use ClassView:

 

private:

    CRect m_rectPrint;

 

Using ClassView to add a CRect data member to the CStringView class.

 

Figure 7: Using ClassView to add a CRect data member to the CStringView class.

 

Entering the member variable type and name.

 

Figure 8: Entering the member variable type and name.

 

Visual C++ code segment

 

Listing 4.

 

Edit three CMymfc21Doc member functions in the file Mymfc21Doc.cpp. AppWizard generated skeleton OnNewDocument() and Serialize() functions, but we'll have to use ClassWizard to override the DeleteContents() function. We'll initialize the poem document in the overridden OnNewDocument() function. DeleteContents() is called in CDocument::OnNewDocument, so by calling the base class function first we're sure the poem won't be deleted. The text, by the way, is an excerpt from the twentieth poem in Lawrence Ferlinghetti's book A Coney Island of the Mind. Type 10 lines of your choice. You can substitute another poem or maybe your favorite Win32 function description. Add the following code:

 

BOOL CMymfc21Doc::OnNewDocument()

{

    if (!CDocument::OnNewDocument())

        return FALSE;

 

    m_stringArray.SetSize(10);

    m_stringArray[0] = "The pennycandystore beyond the El";

    m_stringArray[1] = "is where I first";

    m_stringArray[2] = "                  fell in love";

    m_stringArray[3] = "                      with unreality";

    m_stringArray[4] = "Jellybeans glowed in the semi-gloom";

    m_stringArray[5] = "of that september afternoon";

    m_stringArray[6] = "A cat upon the counter moved among";

    m_stringArray[7] = "                     the licorice sticks";

    m_stringArray[8] = "                  and tootsie rolls";

    m_stringArray[9] = "           and Oh Boy Gum";

 

    return TRUE;

}

 

Visual C++ code segment

 

Listing 5.

 

The CStringArray class supports dynamic arrays, but here we're using the m_stringArray object as though it were a static array of 10 elements. The application framework calls the document's virtual DeleteContents() function when it closes the document; this action deletes the strings in the array. A CStringArray contains actual objects, and a CObArray contains pointers to objects. This distinction is important when it's time to delete the array elements. Here the RemoveAll() function actually deletes the string objects:

 

void CMymfc21Doc::DeleteContents()

{

    // called before OnNewDocument() and when document is closed

    m_stringArray.RemoveAll();

}

 

Adding the RemoveAll() function to the CMymfc21Doc class.

 

Figure 10: Adding the RemoveAll() function to the CMymfc21Doc class.

 

Visual C++ code segment

 

Listing 6.

 

Serialization isn't important in this example, but the following function illustrates how easy it is to serialize strings. The application framework calls the DeleteContents() function before loading from the archive, so you don't have to worry about emptying the array. Add the following code:

 

void CMymfc21Doc::Serialize(CArchive& ar)

{

    m_stringArray.Serialize(ar);

}

 

Visual C++ code segment

 

Listing 7.

 

Edit the OnInitialUpdate() function in mymfc21View.cpp. You must override the function for all classes derived from CScrollView. This function's job is to set the logical window size and the mapping mode. Add the following code:

 

void CMymfc21View::OnInitialUpdate()

{

       CScrollView::OnInitialUpdate();

    CSize sizeTotal(m_rectPrint.Width(), -m_rectPrint.Height());

    CSize sizePage(sizeTotal.cx / 2, sizeTotal.cy / 2);   // page scroll

    CSize sizeLine(sizeTotal.cx / 100, sizeTotal.cy / 100); // line scroll

    SetScrollSizes(MM_TWIPS, sizeTotal, sizePage, sizeLine);

}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Visual C++ code segment

 

Listing 8.

 

Edit the OnDraw() function in mymfc21View.cpp. The OnDraw() function of class CMymfc21View draws on both the display and the printer. In addition to displaying the poem text lines in 10-point roman font, it draws a border around the printable area and a crude ruler along the top and left margins. OnDraw() assumes the MM_TWIPS mapping mode, in which 1 inch = 1440 units. Add the code shown below.

 

void CMymfc21View::OnDraw(CDC* pDC)

{

    int        i, j, nHeight;

    CString    str;

    CFont      font;

    TEXTMETRIC tm;

 

    CMymfc21Doc* pDoc = GetDocument();

    // Draw a border - slightly smaller to avoid truncation

    pDC->Rectangle(m_rectPrint + CRect(0, 0, -20, 20));

    // Draw horizontal and vertical rulers

    j = m_rectPrint.Width() / 1440;

    for (i = 0; i <= j; i++)

    {

        str.Format("%02d", i);

        pDC->TextOut(i * 1440, 0, str);

    }

    j = -(m_rectPrint.Height() / 1440);

    for (i = 0; i <= j; i++)

    {

        str.Format("%02d", i);

        pDC->TextOut(0, -i * 1440, str);

    }

    // Print the poem 0.5 inch down and over;

    // use 10-point roman font

    font.CreateFont(-200, 0, 0, 0, 400, FALSE, FALSE, 0, ANSI_CHARSET,

                    OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,

                    DEFAULT_QUALITY, DEFAULT_PITCH | FF_ROMAN, "Times New Roman");

    CFont* pOldFont = (CFont*) pDC->SelectObject(&font);

    pDC->GetTextMetrics(&tm);

    nHeight = tm.tmHeight + tm.tmExternalLeading;

    TRACE("font height = %d, internal leading = %d\n", nHeight, tm.tmInternalLeading);

    j = pDoc->m_stringArray.GetSize();

    for (i = 0; i < j; i++)

    {

        pDC->TextOut(720, -i * nHeight - 720, pDoc->m_stringArray[i]);

    }

    pDC->SelectObject(pOldFont);

    TRACE("LOGPIXELSX = %d, LOGPIXELSY = %d\n", pDC->GetDeviceCaps(LOGPIXELSX),

          pDC->GetDeviceCaps(LOGPIXELSY));

    TRACE("HORZSIZE = %d, VERTSIZE = %d\n", pDC->GetDeviceCaps(HORZSIZE),

          pDC->GetDeviceCaps(VERTSIZE));

}

 

Visual C++ code segment

 

Listing 9.

 

Edit the OnPreparePrinting() function in mymfc21View.cpp. This function sets the maximum number of pages in the print job. This example has only one page. It's absolutely necessary to call the base class DoPreparePrinting() function in your overridden OnPreparePrinting() function. Add the following code:

 

BOOL CMymfc21View::OnPreparePrinting(CPrintInfo* pInfo)

{

       pInfo->SetMaxPage(1);

    return DoPreparePrinting(pInfo);

}

 

Visual C++ code segment

 

Listing 10.

 

Edit the constructor in mymfc21View.cpp. The initial value of the print rectangle should be 8-by-15 inches, expressed in twips (1 inch = 1440 twips). Add the following code:

 

CMymfc21View::CMymfc21View() : m_rectPrint(0, 0, 11520, -15120)

{

       // TODO: add construction code here

}

 

Visual C++ code segment

 

Listing 11.

 

Testing the MYMFC21 Application

 

When the application starts, you can split the window by choosing Split from the View menu or by dragging the splitter boxes at the left and top of the scroll bars. Figure 11 shows a typical single view window with a four-way split. Multiple views share the scroll bars.

 

MYMFC21 output, a single view window with a four-way split.

 

Figure 11: MYMFC21 output, a single view window with a four-way split.

 

 

Continue on next module...part 2.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Further reading and digging:

  1. MSDN MFC 7.0 class library online documentation.

  2. MSDN MFC 9.0 class library online documentation - latest version.

  3. MSDN Library

  4. Windows data type.

  5. Win32 programming Tutorial.

  6. The best of C/C++, MFC, Windows and other related books.

  7. Unicode and Multibyte character set: Story and program examples.

 

 


 

| Tenouk C & C++ | MFC Home | Printing & Print Preview 2 | Splitter Windows & Multiple Views 2 | Download | Site Index |