Click here to Skip to main content
Click here to Skip to main content

Another splitter control for dialog

By , 12 Jul 2002
 
Sample Image

Introduction

I'm a student and very interested in VC++. I often enter this web site to get free source code. I was in need of a splitter in a dialog. I downloaded one but it's very complex and I felt it was difficult to use the control (although it's very powerful) so I made one for myself. Maybe, it's not useful for you, but if there's only one person who thinks it's useful, I will be very happy. Sometimes you don't need good skill, just a good idea, and by this simple way a useful piece of code will be produced. My splitter control is one of this kind.

How to use the CSplitterControl class

First of all, add two files SplitterControl.h and SplitterControl.cpp to the project. Remember to add #include "splittercontrol.h" to the header file of the class which uses it.

Add member varible to the dialog class

 protected: 
    CSplitterControl     m_wndSplitter1; 

Now, we create the control by calling it's create function. This code would appear in the OnInitDialog or OnCreate function.

BOOL CSPDemoDlg::OnInitDialog()
{ 
	...
	pWnd = GetDlgItem(IDC_SPLITTER1);
	pWnd->GetWindowRect(rc);
	ScreenToClient(rc);
	m_wndSplitter1.Create(WS_CHILD | WS_VISIBLE, rc, this, IDC_SPLITTER1);
	m_wndSplitter1.SetRange(50, 50, -1);
	...

There is a tip here. Instead of calculating the rect for the splitter, we add a static control on the dialog (by resource editor), give it an ID (IDC_SPLITTER1) and make it invisible. Size it and locate in the resource editor, and then call the function GetWindowRect(rc) to move the m_wndSplitter1 to the rect.

And here is the code for resizing controls on the dialog when the user moves the splitter control.

//
// LRESULT CSPDemoDlg::DefWindowProc(UINT message, WPARAM wParam, LPARAM lParam) 
{
	if (message == WM_NOTIFY)
	{
		if (wParam == IDC_SPLITTER1)
		{	
			SPC_NMHDR* pHdr = (SPC_NMHDR*) lParam;
			DoResize1(pHdr->delta);
		}
	}
	
	return CDialog::DefWindowProc(message, wParam, lParam);
}
//
void CSPDemoDlg::DoResize1(int delta)
{
	// Change the width for m_wndType, m_lstItem, m_txtContent	
	CSplitterControl::ChangeWidth(&m_wndType, delta);
	CSplitterControl::ChangeWidth(&m_lstItem, -delta, CW_RIGHTALIGN);
	CSplitterControl::ChangeWidth(&m_txtContent, -delta, CW_RIGHTALIGN);
	Invalidate();
	UpdateWindow();
}

About the class CSplitterControl and it's functions

Here's the interface for the class CSplitterControl
class CSplitterControl : public CStatic
{
	// Construction
public:
	CSplitterControl();

	// Attributes
protected:
	BOOL m_bIsPressed;
	int m_nType;
	int m_nX, m_nY;
	int m_nMin, m_nMax;
	int m_nSavePos; // Save point on the lbutton down

public:
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CSplitterControl)
	//}}AFX_VIRTUAL

	// Implementation
public:
	static void ChangePos(CWnd* pWnd, int dx, int dy);
	static void ChangeWidth(CWnd* pWnd, int dx, DWORD dwFlag = CW_LEFTALIGN);
	static void ChangeHeight(CWnd* pWnd, int dy, DWORD dwFlag = CW_TOPALIGN);

public:
	void SetRange(int nMin, int nMax);
	void SetRange(int nSubtraction, int nAddition, int nRoot);
	int GetStyle();
	int SetStyle(int nStyle = SPS_VERTICAL);
	void Create(DWORD dwStyle, const CRect& rect, CWnd* pParent, UINT nID);
	virtual ~CSplitterControl();

	// Generated message map functions
protected:
	virtual void DrawLine(CDC* pDC, int x, int y);
	void MoveWindowTo(CPoint pt);
	//{{AFX_MSG(CSplitterControl)
	afx_msg void OnPaint();
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

// this struct is sent as lparam in WM_NOTIFY message 
typedef struct SPC_NMHDR
{
	NMHDR hdr;
	int delta; // delta : the different position of the splitter before and 
                    // after being moved.
} SPC_NMHDR;

Conclusion

Well, that's all about my code. Maybe, the explanation is not very clear, but I hope you'll find it easy to use. No special skill, you see. Very simple. Thanks for reading my article. Please give your ideas as to whether you like or hate it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Hung Nguyen
United States United States
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralNice work!memberjcleung6 Nov '09 - 15:35 
It's very useful to me,thanks 4 ur share!
GeneralI want to display a Bitmap on the splittermemberlan_63738369 Aug '09 - 17:22 
I want to display a Bitmap on the splitter .What should I do?Thx
GeneralOne problemmembermxs8102 Apr '09 - 0:19 
This is a good job,But I found a problem when I use it.
One dialog is Maximize,before it is restored.If I click the splitter and move down in this time,
it will move to the bottom of the dialog.And I could not move it up.Confused | :confused:
Could you tell me how to deal with the problem?
Thank you very much. Laugh | :laugh:
Generalnice codememberyusc198626 Feb '09 - 15:48 
Smile | :)
GeneralGood source codememberziguowen27 Nov '08 - 14:15 
Thanks for your source code!It is so good!
General[Message Removed]memberimmetoz6 Oct '08 - 7:51 
Spam message removed
Questionno ideamemberMaryVeranis20 Mar '08 - 4:04 
sorry but i'm an asp.net programmer - can you direct me to what to do with this as far as what goes where? i don't know a thing about c#. i need it to work in an asp.net project so i can't put it uncompiled into my project.
thanks for any help.
GeneralVery nice work. I found a bug and my solutionmembertimyin2 Feb '08 - 21:17 
Hi all,
 
My Problem is:
There is two sub-dialogs in the parent dialog box, i use splitter to split the sub-dialog,
but when i create the splitter dynamically and the ID for this splitter is created in STRING table, when i drag the splitter, the parent dialog exits and the splitter bar is displayed on the screen.
 
My environment: Windows XP and Virtual C++ 6.0
 
Solution:
Comment the line // CStatic::OnLButtonDown(nFlags, point); in function void CSplitterControl::OnLButtonDown(UINT nFlags, CPoint point).
Now i can split the sub-dialogs correctly.
 
Hope it's userful to others.
 
Thanks!
 
BR,
Tim
 
I'm on my way!

GeneralVery nice workmemberAndrea Cacciarru21 Nov '07 - 0:31 
Simple usage for a quite little piece of code to add to my app. Thanks.
 

GeneralNgu bo mememberTo Quang Hiep6 Jun '07 - 23:08 
Doi voi Dialog thi can gi phai sung Splitter
Chi can ve cac control la giai quyet duoc roi
GeneralSlight fixmemberChrisHowe19 Feb '07 - 0:31 
Here is what I think is a fix to the SetRange method...
 
void CSplitterControl::SetRange(int nSubtraction, int nAddition, int nRoot)
{
if (nRoot < 0)
{
CRect rcWnd;
GetWindowRect(rcWnd);
GetParent()->ScreenToClient(rcWnd);
 
The original code was just calling GetWindowRect, which gets the window coordinates in screen space. What you want though is the coordinates in the client space of the parent window.
Questionhow can i make Splitter bar to be not allowed movememberkiranin31 Oct '06 - 0:28 
how can i make splitterbar to be not allow to move
AnswerRe: how can i make Splitter bar to be not allowed movememberNvng YA27 Nov '06 - 23:04 
Yes, I think you can do it with the following code,
 
m_wndSplitter1.SetRange(0, 0, -1);
 
or don't deal with these messages:
ChangePos(CWnd* pWnd, int dx, int dy);
ChangeWidth(CWnd* pWnd, int dx, DWORD dwFlag = CW_LEFTALIGN);
ChangeHeight(CWnd* pWnd, int dy, DWORD dwFlag = CW_TOPALIGN);

AnswerRe: how can i make Splitter bar to be not allowed movemembersharki198711 Aug '10 - 15:54 
Why you want to do this?Splitter is designed for that.
or you can delete these lines as follows:

void CSplitterControl::OnLButtonUp(UINT nFlags, CPoint point)
{
if (pOwner && IsWindow(pOwner->m_hWnd))
{
//pOwner->SendMessage(WM_NOTIFY, nmsp.hdr.idFrom, (LPARAM)&nmsp); }
}

 
and

void CSplitterControl::OnLButtonUp(UINT nFlags, CPoint point)
{
void CSplitterControl::MoveWindowTo(CPoint pt)
{
//MoveWindow(rc);

}

QuestionHow to use your code in SDI application?memberBhushan198014 Jul '06 - 11:54 
Hi,
I want to use this code in SDI application that has multiple views? As you made all your changes in the OnInitDialog handler here, what handlers need to be accessed in case of an SDI application? Is it possible? Thank you.
 

 
Bhushan.
Generalmoving out of dialogmembermirex25 Aug '04 - 4:00 
First I have to say that its a great control, i've been searching for something like this ... but i have one problem .. control can be moved out of the dialog ... is this handled somehow inside the code, or do I have to check out the new splitter position ?
GeneralRe: moving out of dialogmemberatripathi3 Aug '05 - 1:05 
I also run into same problem. following code worked for me
>>>>>
void CSplitterControl::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bIsPressed)
{
CWindowDC dc(NULL);
DrawLine(&dc, m_nX, m_nY);

CPoint pt = point;
ClientToScreen(&pt);
// GetParent()->ScreenToClient(&pt);
 
if (pt.x < m_nMin)
pt.x = m_nMin;
if (pt.y < m_nMin)
pt.y = m_nMin;
 
if (pt.x > m_nMax)
pt.x = m_nMax;
if (pt.y > m_nMax)
pt.y = m_nMax;
 
// GetParent()->ClientToScreen(&pt);
m_nX = pt.x;
m_nY = pt.y;
DrawLine(&dc, m_nX, m_nY);
}
CStatic::OnMouseMove(nFlags, point);
}
>>>>
 

AnswerRe: moving out of dialogmemberbm20 Jul '06 - 22:01 
A better fix to prevent moving outside the parent:
void CSplitterControl::OnMouseMove(UINT nFlags, CPoint point)
{
if (m_bIsPressed)
{
CWindowDC dc(NULL);
DrawLine(&dc, m_nX, m_nY);

CPoint pt = point;
ClientToScreen(&pt);
GetParent()->ScreenToClient(&pt);
 
if (pt.x < m_nMin)
pt.x = m_nMin;
if (pt.y < m_nMin)
pt.y = m_nMin;
 
if (pt.x > m_nMax)
pt.x = m_nMax;
if (pt.y > m_nMax)
pt.y = m_nMax;
 
//>>> BM/BEGIN: prevent moving outside the parent
CRect rParent;
GetParent()->GetClientRect( &rParent );
int minBorder = 10;
int iHeight = rParent.bottom - rParent.top - minBorder;
int iWidth = rParent.right - rParent.left - minBorder;
 
if (pt.x < minBorder)
pt.x = minBorder;
if (pt.y < minBorder)
pt.y = minBorder;
 
if (pt.x > iWidth)
pt.x = iWidth;
if (pt.y > iHeight)
pt.y = iHeight;
//>>> BM/END
 
GetParent()->ClientToScreen(&pt);
m_nX = pt.x;
m_nY = pt.y;
DrawLine(&dc, m_nX, m_nY);
}
CStatic::OnMouseMove(nFlags, point);
}

 
b.minet
Generalone problemmemberregale4 Sep '03 - 1:49 
if you add two buttons under the tree control,.i expect two buttons seem independent,in fact,they have overlappeded
each other.can you help me ?thanks a lotConfused | :confused:
GeneralRe: one problemmemberR.selvam3 Dec '03 - 13:39 
Hi,
 
You set property in Picture Control Visible as false ( Remove default check mark in Visible property )
 

GeneralWorks great for mememberAleemSheikh7 Jul '03 - 20:22 
Cool | :cool: I am using it in a calender application where there are multiple controls on a single dialog and it works great for me. I am using MFC 7.1. Thanks a lot.
 
M.Aleem Sheikh
Abacusoft
Generalsmall TCHAR.H -compatible modificationmembernanev23 May '03 - 2:08 
In CSplitterControl::Create() function find row
 
CStatic::Create("", dwStyle, rc, pParent, nID);
 
replace it with
 
CStatic::Create(_T(""), dwStyle, rc, pParent, nID);
 
in order to make code TCHAR.H compatible.
GeneralGood work. I've used it but with a little modificationmemberjstuardo8 Mar '03 - 19:29 
Very good work, that class was what I was looking for.
 
The modification I've made is to delete the OnPaint method since I didn't want the splitter bar to be seen, that way, it's more similar with the windows standard splitter, making my application more professional Smile | :) .
 
I have placed the splitter inside a tab control which is inside a controlbar and it looks great.
 
Wink | ;)
 
Thanks
Jaime
GeneralThx a lotmembersinouhe15 Jan '03 - 2:22 
A very simple and helpfull class for an MFC beginner as I am.
Thx again. OMG | :OMG:
 
Sinouhe
GeneralMoak: 84 error(s), 0 warning(s)memberMr Razz4 Jan '03 - 12:06 
copy and paste the header and source. Add to project. Compile. hmmmmmm.
\splittercontrol.h(109) : error C2653: 'std' : is not a class or namespace name.
etc etc.
 
Ok, ive now spent about an hour trying to interpret what this means:
//#include // STL Standard Template Library (add to StdAfx.h).
 
Lets see.. i know what a header file is. Should i include one where it says #include?
or, do should i add a library under project settings, or do i add a line (#include something maybe?)
to the StdAfx.h file? Should i automatically know what this means?
 
hmmm.. probably best to give up.

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web03 | 2.6.130523.1 | Last Updated 13 Jul 2002
Article Copyright 2002 by Hung Nguyen
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid