Figure 2   CMySplitterWnd

mysplit.h

////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal. 
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 5.0 on Windows 95

// Splitter window that lets you change the view in a pane
class CMySplitterWnd : public CSplitterWnd {
public:
    // Function to change the view in a pane
    void ChangeView(int row, int col, CRuntimeClass* pViewClass);

    // functions to get protected CSplitterWnd dimensions
    CSize GetBorderSize()    { return CSize(m_cxBorder,    m_cyBorder); }
    CSize GetSplitterSize() { return CSize(m_cxSplitter, m_cySplitter);  }

    virtual BOOL OnCmdMsg(UINT nID, int nCode, void* pExtra,
                          AFX_CMDHANDLERINFO* pHandlerInfo);
};
mysplit.cpp
////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal. 
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 5.0 on Windows 95
// Implementation for splitter window with changeable view panes
#include "StdAfx.h"
#include "MySplit.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

// This function changes the view in a splitter window
void CMySplitterWnd::ChangeView(int row, int col, CRuntimeClass* pViewClass)
{
    ASSERT(pViewClass->IsDerivedFrom(RUNTIME_CLASS(CView)));

    CView* pView = STATIC_DOWNCAST(CView, GetPane(row, col));
    CFrameWnd* pFrame = pView->GetParentFrame();
    ASSERT(pFrame);

    // set up create context to preserve doc/frame etc.
    CCreateContext cc;
    memset(&cc, sizeof(cc), 0);
    cc.m_pNewViewClass = pViewClass;
    cc.m_pCurrentDoc = pView->GetDocument();
    cc.m_pNewDocTemplate = cc.m_pCurrentDoc ?
        cc.m_pCurrentDoc->GetDocTemplate() : NULL;
    cc.m_pCurrentFrame = pFrame;

    DeleteView(row, col);                // delete old view
    VERIFY(CreateView(row, col,          // create new one
        pViewClass,
        CSize(0,0),                      // will fix in RecalcLayout
        &cc));

    RecalcLayout();                      // recompute layout 

    // initialize the view
    CWnd* pWnd = GetPane(row, col);
    if (pWnd)
        pWnd->SendMessage(WM_INITIALUPDATE);
}

// Splitter wnd function to route commands to all splitter panes/views.
// This lets all panes, not just the active pane, handle messages.
BOOL CMySplitterWnd::OnCmdMsg(UINT nID, int nCode, void* pExtra,
    AFX_CMDHANDLERINFO* pHandlerInfo)
{
    for (int row=0; row<GetRowCount(); row++) {
        for (int col=0; col<GetColumnCount(); col++) {
            if (GetPane(row,col)->OnCmdMsg(nID, nCode, pExtra, pHandlerInfo))
                return TRUE;
        }
    }
    // Call default routing—very important!
    return CSplitterWnd::OnCmdMsg(nID, nCode, pExtra, pHandlerInfo);
}

Figure 3   CformData

forms.h


////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal. 
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 5.0 on Windows 95

// Global information about forms.
// Class hides implementation of mapping.
class CFormData {
private:
    UINT  m_nCurrentForm;
public:
    CFormData();
    CRuntimeClass*    GetViewClass(UINT iWhich);
    LPCTSTR           GetDisplayName(UINT iWhich);
    UINT              GetMaxNumForms();
    UINT              GetCurrentForm() { return  m_nCurrentForm; }
    void              SetCurrentForm(UINT iWhich);
};

extern CFormData FormData; // global instance to access through

forms.cpp


////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal. 
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 5.0 on Windows 95
#include "StdAfx.h"
#include "resource.h"
#include "Forms.h"
#include "View1.h"
#include "View2.h"
#include "View3.h"
#include "View4.h"

CFormData FormData; // global instance

const NFORMS = 4; // total number of forms 

// This structure links form index to form name and view class
static struct {
    LPCTSTR          lpszName;    // Display name
    CRuntimeClass* pClass;        // MFC runtime class
} Forms [NFORMS] = {
    { _T("Form 1"), RUNTIME_CLASS(CView1) },
    { _T("Form 2"), RUNTIME_CLASS(CView2) },
    { _T("Form 3"), RUNTIME_CLASS(CView3) },
    { _T("Form 4"), RUNTIME_CLASS(CView4) }
};

CFormData::CFormData()
{
    SetCurrentForm(0);
}

void CFormData::SetCurrentForm(UINT iWhich)
{
    ASSERT(0<=iWhich && iWhich<NFORMS);
    m_nCurrentForm = iWhich;    
}

CRuntimeClass* CFormData::GetViewClass(UINT iWhich)
{
    ASSERT(0<=iWhich && iWhich<NFORMS);
    return Forms[iWhich].pClass;
}

LPCTSTR CFormData::GetDisplayName(UINT iWhich)
{
    ASSERT(0<=iWhich && iWhich<NFORMS);
    return Forms[iWhich].lpszName;    
}

UINT CFormData::GetMaxNumForms()
{
    return NFORMS;
}

Figure 6   CmyView

view.h


////////////////////////////////////////////////////////////////
// 1998 Microsoft Systems Journal. 
// If this code works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
// Compiles with Visual C++ 5.0 on Windows 95
// 
class CMyView : public CView {
private:
    CRect m_rcClient;         // client area rectangle
    CRgn  m_hotRegion;        // elliptic region
    BOOL  m_bHilite;          // highlight the ellipse?
    BOOL  m_bTrackLeave;      // I am tracking mouse leave

public:
    virtual ~CMyView();
    CMyDoc* GetDocument() { return (CMyDoc*)m_pDocument; }

    virtual void OnDraw(CDC* pDC);
    BOOL GetHighlight(CPoint pt);

protected:
    DECLARE_DYNCREATE(CMyView)
    CMyView();
    afx_msg void    OnMouseMove(UINT nFlags, CPoint pt);
    afx_msg LPARAM  OnMouseLeave(WPARAM wp, LPARAM lp);
    afx_msg void    OnSize(UINT nType, int cx, int cy);
    DECLARE_MESSAGE_MAP()
};

view.cpp


////////////////////////////////////////////////////////////////
// FLYBY 1998 Microsoft Systems Journal. 
// If this program works, it was written by Paul DiLascia.
// If not, I don't know who wrote it.
//
#include "StdAfx.h"
#include "Flyby.h"
#include "Doc.h"
#include "View.h"
#include "Mouse.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

IMPLEMENT_DYNCREATE(CMyView, CView)

BEGIN_MESSAGE_MAP(CMyView, CView)
    ON_WM_MOUSEMOVE()
    ON_WM_SIZE()
    ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)
END_MESSAGE_MAP()

CMyView::CMyView()
{
    m_bHilite = -1;            // invalid state
    m_bTrackLeave = FALSE;    // not traking mouse
}

CMyView::~CMyView()
{
}

//////////////////
// Draw ellipse within client area.
// If mouse is outside the ellipse, draw gray; else red
//
void CMyView::OnDraw(CDC* pDC)
{
    // create brush w/appropriate color: red/gray.
    if (m_bHilite==-1) {
        CPoint pt = Mouse;        // mouse pos in screen coords 
        ScreenToClient(&pt);      // convert to client
        m_bHilite = GetHighlight(pt);
    }
    CBrush brush(m_bHilite ? RGB(255,0,0) : RGB(192,192,192));

    // select brush and draw ellipse
    CGdiObject *pOldBrush = pDC->SelectObject(&brush);
    pDC->Ellipse(&m_rcClient);
    pDC->SelectObject(pOldBrush);
}

//////////////////
// Window size changed: update client rectangle and elliptic region.
//
void CMyView::OnSize(UINT nType, int cx, int cy)
{
    m_rcClient.SetRect(0,0,cx,cy);
    m_hotRegion.DeleteObject();
    m_hotRegion.CreateEllipticRgnIndirect(&m_rcClient);
}

//////////////////
// Determine if I should highlight the ellipse based on mouse coords.
// That is, if point is inside ellipse and I have the focus.
//
BOOL CMyView::GetHighlight(CPoint pt)
{
    return m_hotRegion.PtInRegion(pt) &&
        CWnd::GetFocus()==this;
}

//////////////////
// Handle mouse move message: highlight or unhighlight ellipse.
//
void CMyView::OnMouseMove(UINT nFlags, CPoint pt)
{
    if (!m_bTrackLeave) {
        // First time since mouse entered my window: request leave notification
        TRACKMOUSEEVENT tme;
        tme.cbSize = sizeof(tme);
        tme.hwndTrack = m_hWnd;
        tme.dwFlags = TME_LEAVE;
        _TrackMouseEvent(&tme);
        m_bTrackLeave = TRUE;
    }

    BOOL bHilite = GetHighlight(pt);
    if (bHilite != m_bHilite) {
        // mouse has either left or entered the ellipse: repaint
        m_bHilite = bHilite;
        Invalidate(FALSE);
        UpdateWindow();
    }
}

//////////////////
// Mouse left the window.
//
LPARAM CMyView::OnMouseLeave(WPARAM wp, LPARAM lp)
{
    m_bTrackLeave = FALSE;            // no longer tracking
    if (m_bHilite) {
        m_bHilite = FALSE;            // don't highlight
        Invalidate(FALSE);            // force repaint...
        UpdateWindow();
    }
    return 0;
}