Visual C++ 6 Unleashed

Visual C++ 6 Unleashed

By MICKEY WILLIAMS and David Bennett

Adding Splitters to Your Application

You probably have seen several applications that provide the capability of splitting the view window into two (or more) different views of the same object. This functionality is supported by MFC and actually can be added by the MFC AppWizard or by inserting the Split Bars component from the Component Gallery. Let's take a look at just how this works.

First, two types of splitters are available: static and dynamic. If you want to set up your application to have a predefined number of windows in its view, and you do not want the user to be able to define new splits at runtime, you use static splitters. If you want to give the user the capability to split your views at runtime, you use dynamic splitters.

MFC's implementation of splitters, or split bars, is based on the CSplitterWnd class. Objects of this class are designed to reside in the frame windows that will hold your views. In SDI apps, this is the main frame; in MDI apps, it is the MDI child frame. You need to add a declaration to your frame class to include a CSplitterWnd object:

CSplitterWnd m_wndSplitter;

This code is used for both the static and dynamic flavors of splitters. For now, let's look at how to implement dynamic splitters.

Dynamic Splitters

You need to override the OnCreateClient() function of your frame class. OnCreateClient() is called from OnCreate() when your application creates the view that will live in the frame. Your implementation should look something like this example generated by inserting the Split Bars component:

BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
    // CG: The following block was added by the Split Bars component.
    {
        if (!m_wndSplitter.Create(this,
                                  2, 2,
                                  CSize(10, 10),
                                  pContext))
        {
            TRACE0("Failed to create split bar ");
            return FALSE;    // failed to create
        }
        return TRUE;
    }
}

Here you see that the CSplitterWnd::Create() function is called. The Create() function takes several parameters, beginning with the parent window, which will be the frame. The next two parameters dictate the maximum number of rows and columns that may be created. In the current implementation, this limit is 2. If you need more, you have to use static splitters. The next parameter is a SIZE structure specifying the minimum size allowed for a pane.

The last parameter used in the example is a pointer to a CCreateContext object. In most cases, this is simply the pointer that is passed to the OnCreateClient() function. Optionally, you can specify styles and a child window ID in the Create() function. At this point, your application is all set to go. OnCreateClient() is called when the child frame needs to create a view, which then calls Create() for the CSplitterWnd object, which then creates the actual view based on your document templates.

Creating Different Views

If you want to create a different type of view in the new pane when the user splits the window, you can do so, but you first have to create your own class based on CSplitterWnd. In your new class, you have to provide an override for the CreateView() function:

BOOL CMySplitterWnd::CreateView(int row, int col,
        CRuntimeClass* pViewClass, SIZE sizeInit,
        CCreateContext* pContext)
{
    if(column == 0)
    {
    return CSplitterWnd::CreateView(row, col, pViewClass, sizeInit, pContext);
    }
    else
    {
    return CSplitterWnd::CreateView(row, col, RUNTIME_CLASS(CRightView),
sizeInit, pContext);
    }
}  // end CreateView()

In this example, you create a view of type CRightView in any panes that are not in column 0 (the leftmost column). You also can create a view based on a new document in a similar fashion, although you have to create your own CCreateContext object to pass to the CreateView() function. In this object, you can pass a different document template for the new view.

Static Splitters

Working with static splitters is similar to working with dynamic splitters, but some important differences exist. First, you should call CSplitterWnd::CreateStatic() instead of Create(). You also need to create the views yourself—if you don't, your app will crash. To do this, call CSplitterWnd::CreateView() for each pane that you have defined, as in the following example:

BOOL CChildFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
    int nCol;

    if (!m_wndSplitter.CreateStatic(this, 1, 3))
    {
        TRACE0("Failed to create split bar ");
        return FALSE;    // failed to create
    }
    for(nCol=0; nCol < 3; nCol++)
    {
        if(!m_wndSplitter.CreateView(0, nCol,
            RUNTIME_CLASS(CMyView),
            CSize(50, 100), pContext))
        {
            TRACE0("Failed to create view ");
            return FALSE;
        }
        return TRUE;
    }  // end for
}  // end OnCreateClient()

This example defines three panes, arranged horizontally, that all use the same view class and document. If you want to use a different view class or document, you can change this, as with the previous example of dynamic splitters.

Share ThisShare This

Informit Network