CSplitterWnd in a Dialog based Application

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 = ...;
	m_wndSplitter.MoveWindow(&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
	public:
	CxSplitterWnd() {};
	virtual ~CxSplitterWnd() {}; 

	// Operations
	public: 
	// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CxSplitterWnd)
	//}}AFX_VIRTUAL 

	// Implementation
	public: 
	// 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
	protected:
	//{{AFX_MSG(CxSplitterWnd)
	// NOTE - the ClassWizard will add and remove member functions here.
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

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__;
#endif 

// 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)
//{{AFX_MSG_MAP(CxSplitterWnd)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP() 

CWnd* CxSplitterWnd::GetActivePane(int* pRow, int* pCol)
{
	ASSERT_VALID(this); 
	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;
	pPane->SetFocus();
} 

void CxSplitterWnd::StartTracking(int ht)
{
ASSERT_VALID(this);
	if (ht == noHit)
		return; 
	// GetHitRect will restrict 'm_rectLimit' as appropriate
	GetInsideRect(m_rectLimit); 
	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);
	}
	else
	{
		// only hit one bar
		GetHitRect(ht, m_rectTracker);
	} 

	// steal focus and capture
	SetCapture();
	SetFocus(); 
	// make sure no updates are pending
	RedrawWindow(NULL, NULL, RDW_ALLCHILDREN | RDW_UPDATENOW); 
	// set tracking state and appropriate cursor
	m_bTracking = TRUE;
	OnInvertTracker(m_rectTracker);
	if (m_bTracking2)
	OnInvertTracker(m_rectTracker2);
	m_htTrack = ht;
	SetSplitCursor(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



Comments

  • Nike Display Max 1 FB publicity, have a strong color character, the chic shoes

    Posted by Geozyoceada on 04/24/2013 07:49am

    In the summer in a pane backing bowels the imperturbable sprite seems to be a wholesome choice, but if the sprite "feet"? Resolution also give you a lapse, bring a sustenance! This summer, Nike and Sprite [url=http://fossilsdirect.co.uk/glossarey.cfm]nike huarache[/url] and his sneakers to a fuse of enduring snow spread of callow, off-white and downcast color scheme in the definitive Nike Air Max 1 shoes let slip a refreshing cool scent.[url=http://fossilsdirect.co.uk/glossarey.cfm]nike huarache free[/url] Summer is the yet to select a clean shoe, shoes should be a obedient choice. Qualifying series Nike Air Max HomeTurf borough recently finally comes up, this series in the immortal Breath Max shoes to London, Paris and Milan the three paid tribute to the iconic megalopolis of Europe, combined with the characteristics of the three cities, Feeling Max 1 HYP,Make public Max 90 HYP,Connected Max 1 and shoes such as Style Max 95, combined [url=http://markwarren.org.uk/property-waet.cfm]nike air max 90[/url] with the Hyperfuse, as marvellously as a collection of materials, such as suede, Whether you hankering functional or retro-everything.

    Reply
  • How to solve crack in release mode?

    Posted by Legacy on 10/24/2002 12:00am

    Originally posted by: mihee

    in debug mode, i solve ASSERT problem with Christian's comment.
    but crack fired in release mode...
    how to solve?

    Reply
  • Works nicely

    Posted by Legacy on 05/30/2001 12:00am

    Originally posted by: Richard Cullen

    Thanks for this article - with the fix from Christian it seems to work nicely.

    - Richard

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

Top White Papers and Webcasts

  • 10 Rules that Make or Break Enterprise App Development Projects In today's app-driven world, application development is a top priority. Even so, 68% of enterprise application delivery projects fail. Designing and building applications that pay for themselves and adapt to future needs is incredibly difficult. Executing one successful project is lucky, but making it a repeatable process and strategic advantage? That's where the money is. With help from our most experienced project leads and software engineers, …

  • Between contractors and employees, there is a great deal of risk surrounding the privacy and security of sensitive data in the healthcare industry. When a breach is suspected, the law requires that healthcare organizations quickly launch an investigation to find the source and scope of the issue. These investigations can be quite costly, to say nothing of the penalties for the breach itself and the damage to reputation and brand. This white paper details new affordable software tools that can help healthcare …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds