Training
Certifications
Books
Special Offers
Community




 
Microsoft® Mastering: MFC Development Using Microsoft Visual C++® 6.0
Author Microsoft Corporation
Pages 624
Disk 1 Companion CD(s)
Level Intermediate
Published 02/23/2000
ISBN 9780735609259
ISBN-10 0-7356-0925-X
Price(USD) $49.99
To see this book's discounted price, select a reseller below.
 

More Information

About the Book
Table of Contents
Sample Chapter
Index
Related Series
Related Books
About the Author

Support: Book & CD

Rate this book
Barnes Noble Amazon Quantum Books

 


Chapter 4: Implementing View Classes (continued)


Creating Static Splitter Windows

A static splitter window is constructed along with the frame window at application startup. The user cannot create or destroy a static splitter window.

To create a static splitter window

  1. Add a CSplitterWnd object to the CMainFrm class in an SDI application (or to the CChildFrame class in an MDI application).

  2. NOTE:
    You can use MFC AppWizard or the Component and Controls Gallery to add the splitter object. However, you will need to replace the code generated by MFC AppWizard or the Component and Controls Gallery to make it appropriate for a static splitter window.

  3. Add the classes for the additional views that you want in your application.

  4. NOTE:
    You can use ClassWizard to add new view classes.

  5. Associate each view with the appropriate pane of the splitter window.

When you use MFC AppWizard to create an application, you choose the base class for the view in Step 6. MFC AppWizard adds this single view class to your application. You can then use ClassWizard to derive other view classes from appropriate view base classes and display each in a pane of a static splitter window.

To implement a static splitter window in an application

  1. Initialize the CSplitterWnd object by calling the CSplitterWnd::CreateStatic function in the OnCreateClient function of the frame class.
  2. Associate the appropriate views with each pane. To do so, call the CSplitterWnd::CreateView function for each pane that you created in the call to CSplitterWnd::CreateStatic.

The following sample code shows how to create and implement a static splitter window by using the OnCreateClient function. To copy this code for use in your own projects, see "Implementing a Static Splitter Window" on the accompanying CD-ROM.

// Implementing an application with a static splitter window
// Samples\CH04\Splitter
// MainFrm.h : interface of the CMainFrame class

class CMainFrame : public CFrameWnd
{
...
protected:
CSplitterWnd m_wndSplitter;
...
};

// Samples\CH03\Splitter
// MainFrm.cpp : implementation of the CMainFrame class

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs,
CCreateContext* pContext)
{
// ...
// This is the code for a static splitter.
CRect cr;
GetClientRect(&cr);

CSize paneSize(cr.Width(), cr.Height() / 2);

int rc;
m_wndSplitter.CreateStatic(this, 2, 1);
   rc = m_wndSplitter.CreateView(0, 0,
        RUNTIME_CLASS(CSplitterView),
        paneSize, pContext);

if (FALSE == rc)
return rc;

rc = m_wndSplitter.CreateView(1, 0,
        RUNTIME_CLASS(CItalicsView),
        paneSize, pContext);
return rc;
}

Command Handler Issues

In a dynamic splitter application, command handlers are generally placed in the view class. The view class has the easiest access to the document, and commands often modify the data in the document.

However, a static splitter application generally has multiple views. Depending on what is appropriate for your application, you must decide where to place your command handlers. If you want the same commands enabled regardless of which view has focus, place the handlers in the frame class. If you want each view to have its own set of handlers, add the appropriate handlers to each view class.

Coordinating Updates in the Views

In applications that use different types of views, calling UpdateAllViews is not the easiest solution for updating data. For information about coordinating multiple views, see "Coordinating Multiple Interrelated Views" on page 183 in this chapter.

Lab 4.1: Adding a Splitter Bar

In this lab, you will add a splitter bar to a single document interface (SDI) application.

To see the demonstration "Lab 4.1 Demonstration," see the accompanying CD-ROM.

Estimated time to complete this lab: 20 minutes

To complete the exercises in this lab, you must have the required software. For detailed information about the labs and setup for the labs, see "Labs" in "About This Course."

The code that forms the starting point for this lab is located in the folder <install folder>\Labs\Ch04\Lab4.1\Ex01.

The solution code for this lab is located in the folder <install folder>\Labs\Ch04\Lab4.1\Ex01\Solution.

Objectives

After completing this lab, you will be able to:

  • Add a class to an application using ClassWizard.
  • Add a static splitter bar to a window to create a split pane.

Prerequisites

There are no prerequisites for this lab.

Exercises

The following exercise provides practice working with the concepts and techniques covered in this chapter:

  • Exercise 1: Adding a Splitter Window
  • In this exercise, you will add a splitter bar to an SDI window.

Exercise 1: Adding a Splitter Window

The code that forms the starting point for this exercise is in <install folder>\Labs\Ch04\Lab4.1\Ex01.

In this exercise, you will add a splitter bar to an SDI application.

Create a new CSplitter class

  1. On the View menu, click ClassWizard.
  2. Click Add Class, and then click New.
  3. Set the name of the class to CSplitter, and base the class on the generic CWnd class. Accept the defaults for the other fields. Click OK.
  4. Figure 4-5.

    Figure 4-5.


    NOTE:
    ClassWizard does not present CSplitterWnd as a base class. You can change the base class directly.

  5. Edit the file Splitter.h. Click CSplitter in FileView, then click Go to Definition.
  6. Change the declaration line of CSplitter from:

    class CSplitter : public CWnd  

    to:

    class CSplitter : public CSplitterWnd  

  7. Add a method to get the protected width of the splitter window to the public attributes section of the CSplitter definition as follows:
  8. int GetSplitterWidth() const { return m_cxSplitter; }  

  9. Open the file Splitter.cpp and update the message map declaration. It reads:
  10. BEGIN_MESSAGE_MAP(CSplitter, CWnd)
    //{{AFX_MSG_MAP(CSplitter)

  11. Change the first line to reference CSplitterWnd instead of CWnd as follows:
  12. BEGIN_MESSAGE_MAP(CSplitter, CSplitterWnd)  

Add a reference to the splitter in the MainFrame object

  1. Open the file MainFrm.h.
  2. Add a protected CSplitter member to the class definition as follows:
  3. // splitter bar embedded members
    CSplitter m_wndSplitter;

  4. Use ClassWizard to add an OnCreateClient handler. ClassWizard creates a reference to the OnCreateClient handler in MainFrm.h and a blank implementation in the file MainFrm.cpp.
  5. Figure 4-6.

    Figure 4-6.

The major implementation task in adding a splitter bar to an application is to create the split window itself. Because only two files are allowed to be active, you use static splitter windows. Put the bar in the middle of the frame. For more information, see "Multiple Document Types, Views, and Frame Windows" under "Static splitter windows" in the MSDN Library Visual Studio 6.0.

Add code to the OnCreateClient handler to create the splitter window

  1. Create the static splitter window by adding a call to CSplitterWnd::CreateStatic as follows:
  2. m_wndSplitter.CreateStatic (this, 1, 2, WS_CHILD);  

    CSplitterWnd::CreateStatic sets up a constant number and arrangement of splitter panes.

  3. Size the splitter windows to two equal panes as follows:
  4. SIZE size;
    CRect rect;
    GetClientRect(&rect);
    size.cx = (rect.right - m_wndSplitter.GetSplitterWidth())/2;
    size.cy = rect.bottom;

  5. Attach the views to the windows as follows:
  6. m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CDiffView), size, 
    pContext);
    m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CDiffView), size,
    pContext);
    SetActiveView((CView *)m_wndSplitter.GetPane(0,1));

  7. Show the splitter window as follows:
  8. m_wndSplitter.ShowWindow(SW_SHOWNORMAL);
    m_wndSplitter.UpdateWindow();
    return TRUE

The following sample code shows an example of how your code should look. To copy this code for use in your own projects, see "Lab 4.1.1 OnCreateClient" on the accompanying CD-ROM.

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/, 
CCreateContext* pContext)
{
// Create a static splitter window with two side-by-side panes

if(!m_wndSplitter.CreateStatic (this,1,2,WS_CHILD))
{
return FALSE;
}

// Calculate the size of the splitter panes
SIZEsize;
CRect rect;
GetClientRect(&rect);
   size.cx = (rect.right - m_wndSplitter.GetSplitterWidth())/2;
size.cy = rect.bottom;

//set the views
m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CDiffView), size,
pContext);
m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CDiffView), size,
pContext);
SetActiveView((CView *)m_wndSplitter.GetPane(0,1));

//show the splitter
m_wndSplitter.ShowWindow(SW_SHOWNORMAL);
m_wndSplitter.UpdateWindow();

return TRUE;
}
Build, and run the Diff application

  1. In MainFrm.cpp, include Splitter.h, the file DiffDoc.h., and the file DiffView.h. Splitter.h must be included before MainFrm.h, because there is a CSplitter member of CMainFrame.
  2. #include "splitter.h"
    #include "MainFrm.h"
    #include "diffdoc.h"
    #include "diffview.h"

  3. In the file Diff.cpp, include Splitter.h before MainFrm.h
  4. #include "splitter.h"
    #include "MainFrm.h"

  5. Build and run the application. You will notice that you can reposition the splitter bar, but you cannot delete or add splitters.

The solution code for this exercise is located in the folder <install folder>\Labs\Ch04\Lab4.1\Ex01\Solution.

Implementing Form Views

The CFormView class provides a window whose client area contains dialog box controls. These controls support entering, viewing, or altering data that is usually found in a form-based, data-access application.

In this section, you will look at creating and implementing form views derived from the CFormView class. This section also provides an overview of the database view classes.

User-Defined Form Views

To create a user-defined form view, you must create controls on the form, and handle updating the view and the document. Optionally, you can provide customized printing support.

Choosing CFormView as the base class for your application in Step 6 of MFC AppWizard provides a "blank" form, which you can customize with the appropriate controls. The following illustration shows the MFC AppWizard - Step 6 dialog box with CFormView selected.

Figure 4-7.

Figure 4-7.

Use the resource editor to open the dialog box resource in the .rc file that is associated with your application view, and to create the controls that you want on the form.

It is important to note that certain properties for the form itself are set by MFC AppWizard and should not be changed. The following table lists the required property settings for a form.

Property name Value
Style Child
Border None
Titlebar Off
Visible Off

Use ClassWizard to add member variables to the form view class. For example, add CString variables for edit controls, BOOL variables for option buttons, and so on.


TIP:
If you have an existing Visual Basic-based application with a form similar to one that you want to use in your form view application, you can import the Visual Basic form into your Visual C++ project. For more information, search for "Using Custom Controls in a Dialog Box" and specifically, "Importing Visual Basic Forms" in MSDN Library Visual Studio 6.0.
Override the OnInitialUpdate function of your view class to perform the initialization you want to occur at application startup, such as resizing the frame to fit the view. Override the OnUpdate function of your view class to initialize the controls on the form with data from the document, as required.

Add message handlers in the view class to respond to messages generated by the controls contained in the view. Typically, you add code to the message handlers to move data from your view to your document. For example, if your document class contains a string, you would place an edit box on the form. Next, in the OnUpdate function, you would initialize the edit control with the current value of the string. Finally, in the handler for the EN_CHANGE message for each edit control, you would add the code to store the new string value in the appropriate member variable in the document.

The sample code on the following page implements a form view with an edit control and three check boxes. To copy this code for use in your own projects, see "Implementing a Form View Application" on the accompanying CD-ROM.

// Samples\CH04\Form
// FormView.cpp : implementation of the CMyFormView class

void CMyFormView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();

// These next 2 calls make the main frame exactly the size
// of form object.
GetParentFrame()->RecalcLayout();
ResizeParentToFit();
}

void CMyFormView::OnUpdate(CView* pSender, LPARAM lHint, CObject* pHint)
{
// Obtain a pointer to the document object.
// Note that OnDraw isn't used, since controls in a dialog
// box can paint themselves.
CFormDoc * pDoc = (CFormDoc *)GetDocument();

// Set the dialog class's member variables to those in the document.
m_dlgPhrase = pDoc->GetPhrase();
m_blue = GetBValue(pDoc->GetColor()) == 255;
m_green = GetGValue(pDoc->GetColor()) == 255;
m_red = GetRValue(pDoc->GetColor()) == 255;

// Cause DDX to occur from dialog object to dialog box.
UpdateData(FALSE);
}
void CMyFormView::OnChangeWelcome()
{
// Cause DDX to occur from dialog box to dialog object.
UpdateData(TRUE);

// Set the document's member variables to those in the dialog object.
CFormDoc * pDoc = (CFormDoc *)GetDocument();
pDoc->SetPhrase(m_dlgPhrase);
}
void CMyFormView::OnColor(UINT nID) 
{
// Cause DDX to occur from dialog box to dialog object.
UpdateData(TRUE);
  // Determine the state of the color check boxes, build an RGB
// value, and store it back into the document.
int r, g, b;
r = m_red ? 255 : 0;
g = m_green ? 255 : 0;
b = m_blue ? 255 : 0;
  CFormDoc * pDoc = (CFormDoc *)GetDocument();
pDoc->SetColor(RGB(r,g,b));

// Now, invalidate the edit control so it repaints itself.
CWnd * pWnd = GetDlgItem(IDC_WELCOME);
pWnd->Invalidate();
}

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

// Note that this function is called before all controls on
// the form are painted. The intent is to only change the
// color of the edit box, so it's necessary to clarify for
// which control this function is being called.
if (GetDlgItem(IDC_WELCOME)->m_hWnd == pWnd->m_hWnd)
{
CFormDoc * pDoc = (CFormDoc *)GetDocument();
pDC->SetTextColor(pDoc->GetColor());
}

return hbr;
}
Optionally, override the OnPrint function in your view class as required.

For more information, search for "CFormView" in MSDN Library Visual Studio 6.0.

Database View Classes

The COleDBRecordView class is derived from CFormView and displays database records in controls. For information about COleDBRecordView, see "COleDBRecordView Class" on page 355 in Chapter 7, "Using OLE DB Templates for Data Access."

In addition, MFC provides the following view classes:

  • CRecordView
  • Provides database forms for applications that use the MFC ODBC classes.

  • CDaoRecordView
  • Provides database forms for applications that use the MFC DAO classes.


Previous    |    Table of Contents    |    Next


Visit Microsoft Press for more information on
Microsoft® Mastering: MFC Development Using Microsoft Visual C++® 6.0


Top of Page


Last Updated: Friday, July 6, 2001