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 routingvery 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;
}