| Tenouk C & C++ | MFC Home | Splitter Windows & Multiple Views 1 | Splitter Windows & Multiple Views 3 | Download | Site Index |


 

 

 

 

 

 

Module 14a:

Splitter Windows and Multiple Views 2

 

 

 

 

 

 

This is a continuation from the previous module... 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. The MYMFC21B Example: A Double View Class SDI Static Splitter

  2. The steps

  3. CHexView class, the cloned CStringView Class

  4. CMainFrame Class

  5. Testing the MYMFC21B Application

 

 

The MYMFC21B Example: A Double View Class SDI Static Splitter

 

In MYMFC21B, we'll extend MYMFC21 by defining a second view class and allowing a static splitter window to show the two views. (The HexView.h and HexView.cpp files are cloned from the original view class.) This time the splitter window works a little differently. Instead of starting off as a single pane, the splitter is initialized with two panes. The user can move the bar between the panes by dragging it with the mouse or by choosing the Window Split menu item. The easiest way to generate a static splitter application is to let AppWizard generate a dynamic splitter application and then edit the generated CMainFrame::OnCreateClient function.

 

 

The steps

 

As usual, begin with the Visual C++ AppWizard, creating an SDI application.

 

Step 4 of 6 AppWizard for MYMFC21B, invoking the Advanced options.

 

Figure 12: Step 4 of 6 AppWizard for MYMFC21B, invoking the Advanced options.

 

Using the split window.

 

Figure 13: Using the split window.

 

Step 6 of 6, renaming the view files, class and using CScrollView as the base view class.

 

Figure 14: Step 6 of 6, renaming the view files, class and using CScrollView as the base view class.

 

Step 6 of 6, renaming the document files and class.

 

Figure 15: Step 6 of 6, renaming the document files and class.

 

MYMFC21B project summary.

 

Figure 16: MYMFC21B project summary.

 

Note that this is an SDI application. Add a CStringArray data member to the CPoemDoc class. Edit the PoemDoc.h header file or use ClassView.

 

public:

    CStringArray m_stringArray;

 

Using ClassView to add a CStringArray data member to the CPoemDoc class.

 

Figure 17: Using ClassView to add a CStringArray data member to the CPoemDoc class.

 

Entering the member variable type and name.

 

Figure 18: Entering the member variable type and name.

 

Visual C++ code segment

 

Listing 12.

 

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 19: Using ClassView to add a CRect data member to the CStringView class.

 

Entering the member variable type and name.

 

Figure 20: Entering the member variable type and name.

 

Visual C++ code segment

Listing 13.

 

Edit three CPoemDoc member functions in the file PoemDoc.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 CPoemDoc::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 14.

 

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 CPoemDoc::DeleteContents()

{

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

    m_stringArray.RemoveAll();

}

 

As in MYMFC21, adding the RemoveAll() function to the document class.

 

Figure 21: As in MYMFC21, adding the RemoveAll() function to the document class.

 

Visual C++ code segment

 

Listing 15.

 

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 CPoemDoc::Serialize(CArchive& ar)

{

    m_stringArray.Serialize(ar);

}

 

Visual C++ code segment

 

Listing 16.

 

Edit the OnInitialUpdate() function in StringView.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 CStringView::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 17.

 

Edit the OnDraw() function in StringView.cpp. The OnDraw() function of class CStringView 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 CStringView::OnDraw(CDC* pDC)

{

    int        i, j, nHeight;

    CString    str;

    CFont      font;

    TEXTMETRIC tm;

 

    CPoemDoc* 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 18.

 

Edit the OnPreparePrinting() function in StringView.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 CStringView::OnPreparePrinting(CPrintInfo* pInfo)

{

    pInfo->SetMaxPage(1);

    return DoPreparePrinting(pInfo);

}

 

Visual C++ code segment

 

Listing 19.

 

Edit the constructor in StringView.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:

 

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

{

}

 

Visual C++ code segment

 

Listing 20.

 

Build and test the application.

 

MYMFC21B program output.

 

Figure 22: MYMFC21B program output.

 

 

CHexView class, the cloned CStringView Class

 

Next, create CHexView by cloning the CStringView. Create the header and source files (HexView.h and HexView.cpp).

 

Creating and adding new CHexView class.

 

Figure 23: Creating and adding new CHexView class.

 

Creating the HexView.h header file.

 

Figure 24: Creating the HexView.h header file.

 

Copy the cloned codes (StringView.h and StringView.cpp) and paste it to the HexView.h and HexView.cpp respectively. It is essentially the same code used for CStringView except for the OnDraw() member function

 

HEXVIEW.H

// HexView.h : interface of the CHexView class

//

/////////////////////////////////////////////////////////////////////////////

 

#if !defined(AFX_CHEXVIEW_H__0A59E9CC_50F1_4B8E_8A3E_C3ED2955CE9D__INCLUDED_)

#define AFX_CHEXVIEW_H__0A59E9CC_50F1_4B8E_8A3E_C3ED2955CE9D__INCLUDED_

 

#if _MSC_VER > 1000

#pragma once

#endif // _MSC_VER > 1000

 

class CHexView : public CScrollView

{

protected: // create from serialization only

       CHexView();

       DECLARE_DYNCREATE(CHexView)

 

// Attributes

public:

       CPoemDoc* GetDocument();

 

// Operations

public:

 

// Overrides

       // ClassWizard generated virtual function overrides

       //{{AFX_VIRTUAL(CHexView)

       public:

       virtual void OnDraw(CDC* pDC);  // overridden to draw this view

       virtual BOOL PreCreateWindow(CREATESTRUCT& cs);

       protected:

       virtual void OnInitialUpdate(); // called first time after construct

       virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);

       virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);

       virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);

       //}}AFX_VIRTUAL

 

// Implementation

public:

       virtual ~CHexView();

#ifdef _DEBUG

       virtual void AssertValid() const;

       virtual void Dump(CDumpContext& dc) const;

#endif

 

protected:

 

// Generated message map functions

protected:

       //{{AFX_MSG(CHexView)

              // NOTE - the ClassWizard will add and remove member functions here.

              //    DO NOT EDIT what you see in these blocks of generated code !

       //}}AFX_MSG

       DECLARE_MESSAGE_MAP()

private:

       CRect m_rectPrint;

};

 

#ifndef _DEBUG  // debug version in CHexView.cpp

inline CPoemDoc* CHexView::GetDocument()

   { return (CPoemDoc*)m_pDocument; }

#endif

 

/////////////////////////////////////////////////////////////////////////////

 

//{{AFX_INSERT_LOCATION}}

// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

 

#endif // !defined(AFX_CHEXVIEW_H__0A59E9CC_50F1_4B8E_8A3E_C3ED2955CE9D__INCLUDED_)

 

 

-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

HEXVIEW.CPP

// HexView.cpp : implementation of the CHexView class

//

 

#include "stdafx.h"

#include "mymfc21B.h"

 

#include "PoemDoc.h"

#include "HexView.h"

 

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[ ] = __FILE__;

#endif

 

/////////////////////////////////////////////////////////////////////////////

// CHexView

 

IMPLEMENT_DYNCREATE(CHexView, CScrollView)

 

BEGIN_MESSAGE_MAP(CHexView, CScrollView)

       //{{AFX_MSG_MAP(CHexView)

              // NOTE - the ClassWizard will add and remove mapping macros here.

              //    DO NOT EDIT what you see in these blocks of generated code!

       //}}AFX_MSG_MAP

       // Standard printing commands

       ON_COMMAND(ID_FILE_PRINT, CScrollView::OnFilePrint)

       ON_COMMAND(ID_FILE_PRINT_DIRECT, CScrollView::OnFilePrint)

       ON_COMMAND(ID_FILE_PRINT_PREVIEW, CScrollView::OnFilePrintPreview)

END_MESSAGE_MAP()

 

/////////////////////////////////////////////////////////////////////////////

// CHexView construction/destruction

 

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

{

       // TODO: add construction code here

}

 

CHexView::~CHexView()

{    }

 

BOOL CHexView::PreCreateWindow(CREATESTRUCT& cs)

{

       // TODO: Modify the Window class or styles here by modifying

       //  the CREATESTRUCT cs

       return CScrollView::PreCreateWindow(cs);

}

 

/////////////////////////////////////////////////////////////////////////////

// CHexView drawing

 

void CHexView::OnDraw(CDC* pDC)

{

    // hex dump of document strings

    int        i, j, k, l, n, nHeight;

    CString    outputLine, str;

    CFont      font;

    TEXTMETRIC tm;

 

    CPoemDoc* pDoc = GetDocument();

    font.CreateFont(-160, 80, 0, 0, 400, FALSE, FALSE, 0,

        ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,

        DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial");

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

    pDC->GetTextMetrics(&tm);

    nHeight = tm.tmHeight + tm.tmExternalLeading;

 

    j = pDoc->m_stringArray.GetSize();

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

        outputLine.Format("%02x   ", i);

        l = pDoc->m_stringArray[i].GetLength();

        for (k = 0; k < l; k++) {

            n = pDoc->m_stringArray[i][k] & 0x00ff;

            str.Format("%02x ", n);

            outputLine += str;

        }

        pDC->TextOut(720, -i * nHeight - 720, outputLine);

    }

    pDC->SelectObject(pOldFont);

}

 

void CHexView::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);

}

 

/////////////////////////////////////////////////////////////////////////////

// CHexView printing

 

BOOL CHexView::OnPreparePrinting(CPrintInfo* pInfo)

{

       pInfo->SetMaxPage(1);

    return DoPreparePrinting(pInfo);

}

 

void CHexView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

       // TODO: add extra initialization before printing

}

 

void CHexView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

       // TODO: add cleanup after printing

}

 

/////////////////////////////////////////////////////////////////////////////

// CHexView diagnostics

 

#ifdef _DEBUG

void CHexView::AssertValid() const

{

       CScrollView::AssertValid();

}

 

void CHexView::Dump(CDumpContext& dc) const

{

       CScrollView::Dump(dc);

}

 

CPoemDoc* CHexView::GetDocument() // non-debug version is inline

{

       ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CPoemDoc)));

       return (CPoemDoc*)m_pDocument;

}

#endif //_DEBUG

 

/////////////////////////////////////////////////////////////////////////////

// CHexView message handlers

 

 

Listing 21: CHexView class, the cloned CStringView class.

 

The CHexView class (HexView.h and HexView.cpp) was written to allow programmers to appreciate poetry. It is essentially the same code used for CStringView except for the OnDraw() member function:

 

void CHexView::OnDraw(CDC* pDC)

{

    // hex dump of document strings

    int        i, j, k, l, n, nHeight;

    CString    outputLine, str;

    CFont      font;

    TEXTMETRIC tm;

 

    CPoemDoc* pDoc = GetDocument();

    font.CreateFont(-160, 80, 0, 0, 400, FALSE, FALSE, 0,

        ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,

        DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, "Arial");

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

    pDC->GetTextMetrics(&tm);

    nHeight = tm.tmHeight + tm.tmExternalLeading;

 

    j = pDoc->m_stringArray.GetSize();

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

        outputLine.Format("%02x   ", i);

        l = pDoc->m_stringArray[i].GetLength();

        for (k = 0; k < l; k++) {

            n = pDoc->m_stringArray[i][k] & 0x00ff;

            str.Format("%02x ", n);

            outputLine += str;

        }

        pDC->TextOut(720, -i * nHeight - 720, outputLine);

    }

    pDC->SelectObject(pOldFont);

}

 

This function displays a hexadecimal dump of all strings in the document's m_stringArray collection. Notice the use of the subscript operator to access individual characters in a CString object.

 

CMainFrame Class

 

As in MYMFC21, the MYMFC21B application's main frame window class needs a splitter window data member and a prototype for an overridden OnCreateClient() function. You can let AppWizard generate the code by specifying Use Split Window, as in MYMFC21. You won't have to modify the MainFrm.h file. The implementation file, MainFrm.cpp, needs both view class headers (and the prerequisite document header), as shown here:

 

#include "PoemDoc.h"

#include "StringView.h"

#include "HexView.h"

 

Visual C++ code segment

 

Listing 22.

 

AppWizard generates dynamic splitter code in the OnCreateClient() function, so you'll have to do some editing if you want a static splitter. Instead of calling CSplitterWnd::Create, you'll call the CSplitterWnd::CreateStatic function, which is tailored for multiple view classes. The following calls to CSplitterWnd::CreateView attach the two view classes. As the second and third CreateStatic() parameters (2, 1) dictate, this splitter window contains only two panes. The horizontal split is initially 100 device units from the top of the window. The top pane is the string view; the bottom pane is the hex dump view. The user can change the splitter bar position but the view configuration cannot be changed.

 

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

    CCreateContext* pContext)

{

    VERIFY(m_wndSplitter.CreateStatic(this, 2, 1));

    VERIFY(m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CStringView), CSize(100, 100), pContext));

    VERIFY(m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CHexView), CSize(100, 100), pContext));

    return TRUE;

}

 

Visual C++ code segment

 

Listing 23.

 

Testing the MYMFC21B Application

 

When you start the MYMFC21B application, the window should look like the one shown below. Notice the separate horizontal scroll bars for the two views.

 

MYMFC21B program output with horizontal split views.

 

Figure 25: MYMFC21B program output with horizontal split views.

 

 

Continue on next module...part 3.

 

 

 

 

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 | Splitter Windows & Multiple Views 1 | Splitter Windows & Multiple Views 3 | Download | Site Index |