CSplitterWnd in a Dialog based Application


Desktop-as-a-Service Designed for Any Cloud ? Nutanix Frame

Download Example Project

Had this problem before. I guess there are some more interested in a solution.

It seems CSplitterWnd is designed to be used in document/view-based applications only.
But by overriding some virtual methods in a derived class, you can make splitter windows based on CSplitterWnd be used in dialog based application, ActiveX-Controls using MFC:

All virtual methods that call GetParentFrame() in its implementation have to be overridden.
I have done this by using existing code except
- that I replaced the call to GetParentFrame() by a call to GetParent().
- all references or pointers to CFrameWnd were changed to references or pointers to CWnd.

I derived a class CxSplitterWnd from the class CSplitterWnd and proceeded as stated above.
Then I used this class in a dialog based application in the same way as any other CWnd derived class.
For example:

class CSampleDialog : public CDialog
	CxSplitterWnd m_wndSplitter; 

BOOL CSampleDlg::OnInitDialog()
	// TODO: Add extra initialization here
	m_wndSplitter.CreateStatic(this, 1, 2);
	m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CSampleView), CSize(50,0), NULL);
	m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CSampleView), CSize(0,0), NULL); 

	CRect rect = ...;

The sample attached is a dialog based application and demonstrates the use of CxSplitterWnd. It does
nothing useful.

This is the new class declaration:

// SplitWnd.h : implementation file
class CxSplitterWnd : public CSplitterWnd
	// Construction
	CxSplitterWnd() {};
	virtual ~CxSplitterWnd() {}; 

	// Operations
	// Overrides
	// ClassWizard generated virtual function overrides

	// Implementation
	// These are the methods to be overridden
	virtual void StartTracking(int ht); 
	virtual CWnd* GetActivePane(int* pRow = NULL, int* pCol = NULL);
	virtual void SetActivePane( int row, int col, CWnd* pWnd = NULL ); 
	virtual BOOL OnCommand(WPARAM wParam, LPARAM lParam);
	virtual BOOL OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult );
	virtual BOOL OnWndMsg( UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult ); 

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

And here the implementation file:
// SplitWnd.cpp : implementation file
#include "stdafx.h"
#include "SplitWnd.h" 

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

// HitTest return values (values and spacing between values is important)
// Had to adopt this because it has module scope 
enum HitTestValue
	noHit = 0,
	vSplitterBox = 1,
	hSplitterBox = 2,
	bothSplitterBox = 3, // just for keyboard
	vSplitterBar1 = 101,
	vSplitterBar15 = 115,
	hSplitterBar1 = 201,
	hSplitterBar15 = 215,
	splitterIntersection1 = 301,
	splitterIntersection225 = 525

// CxSplitterWnd 

BEGIN_MESSAGE_MAP(CxSplitterWnd, CSplitterWnd)
// NOTE - the ClassWizard will add and remove mapping macros here.

CWnd* CxSplitterWnd::GetActivePane(int* pRow, int* pCol)
	CWnd* pView = GetFocus();
	// make sure the pane is a child pane of the splitter
	if (pView != NULL && !IsChildPane(pView, pRow, pCol))
	pView = NULL; 
	return pView;

void CxSplitterWnd::SetActivePane( int row, int col, CWnd* pWnd)
	// set the focus to the pane
	CWnd* pPane = pWnd == NULL ? GetPane(row, col) : pWnd;

void CxSplitterWnd::StartTracking(int ht)
	if (ht == noHit)
	// GetHitRect will restrict 'm_rectLimit' as appropriate
	if (ht >= splitterIntersection1 && ht <= splitterIntersection225)
		// split two directions (two tracking rectangles)
		int row = (ht - splitterIntersection1) / 15;
		int col = (ht - splitterIntersection1) % 15; 
		GetHitRect(row + vSplitterBar1, m_rectTracker);
		int yTrackOffset = m_ptTrackOffset.y;
		m_bTracking2 = TRUE;
		GetHitRect(col + hSplitterBar1, m_rectTracker2);
		m_ptTrackOffset.y = yTrackOffset;
	else if (ht == bothSplitterBox)
		// hit on splitter boxes (for keyboard)
		GetHitRect(vSplitterBox, m_rectTracker);
		int yTrackOffset = m_ptTrackOffset.y;
		m_bTracking2 = TRUE;
		GetHitRect(hSplitterBox, m_rectTracker2);
		m_ptTrackOffset.y = yTrackOffset; 
		// center it
		m_rectTracker.OffsetRect(0, m_rectLimit.Height()/2);
		m_rectTracker2.OffsetRect(m_rectLimit.Width()/2, 0);
		// only hit one bar
		GetHitRect(ht, m_rectTracker);

	// steal focus and capture
	// make sure no updates are pending
	// set tracking state and appropriate cursor
	m_bTracking = TRUE;
	if (m_bTracking2)
	m_htTrack = ht;

// CSplitterWnd command routing 
BOOL CxSplitterWnd::OnCommand(WPARAM wParam, LPARAM lParam)
	if (CWnd::OnCommand(wParam, lParam))
	return TRUE; 
	// route commands to the splitter to the parent frame window
	return GetParent()->SendMessage(WM_COMMAND, wParam, lParam);

BOOL CxSplitterWnd::OnNotify( WPARAM wParam, LPARAM lParam, LRESULT* pResult )
	if (CWnd::OnNotify(wParam, lParam, pResult))
	return TRUE; 
	// route commands to the splitter to the parent frame window
	*pResult = GetParent()->SendMessage(WM_NOTIFY, wParam, lParam);
	return TRUE;

BOOL CxSplitterWnd::OnWndMsg(UINT message, WPARAM wParam, LPARAM lParam, LRESULT* pResult)
	// The code line below is necessary if using CxSplitterWnd in a regular dll
	// AFX_MANAGE_STATE(AfxGetStaticModuleState()); 
	return CWnd::OnWndMsg(message, wParam, lParam, pResult);

Posted: 11 May 1998


  • There are no comments yet. Be the first to comment!

  • You must have javascript enabled in order to post comments.

Leave a Comment
  • Your email address will not be published. All fields are required.

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date