Introduction
I'm developing a CAD/CAM application with MFC using the Document/View framework. In this application, the C<MyProject>View
contains a 3D view with 3D objects. In the CAD/CAM industry, we need different points of views for the 3D Window, so I implemented an Automatic Split function, which tiles the 3D views in 4 panes: Front, Top, Left and Axonometric View.
Unfortunately, I cannot give a sample of the CAD/CAM Application (because it is using third party libraries), but you will find a simple MFC project showing the Automatic split capability, and the focus.
This tutorial explains how to set the focus on the current pane of a Splitted View and how to automatically split a View (without giving the position of the splitterbar
).
Note: For the focus, I’m using code that I found somewhere on the Internet or in a book, but I cannot remember where. If you have written this code, contact me and I will give you credits for your work.
1. Creating the Project
You can use the MFC Application wizard to generate the code of your project:
- Open Visual C++.
- Select File | New | MFCAppWizard (EXE).
- Give a Name (
MyProj
) and a path. - Keep the default options (using direct Finish).
Your project is done; you can compile it and run it.
If you run it, you can see in the Window menu, there is no split option.
2. Adding the Splitter Bars
To do this, you should use the Component Gallery:
- Select Project | Add To Project | Components and Controls.
- Go in Visual C++ Component and select
SplitterBar
. - Select Both / OK and Close.
Now, if you see the CChildFrame
class, you have the OnCreateClient
methods, which creates the SplitterWnd
. Open your Resource View and in the Menu IDR_MYPROJTYPE
, add under Window the entry &Split
with the ID ID_WINDOW_SPLIT
.
Build the executable, and test the "Split
" function (it should work).
3. Creating a New Class which Inherits from CSplitterWnd
Now, you have a new class to work with.
4. Setting the Focus
Add the following 2 public
methods to CSplitterWndEx
:
void OnDrawSplitter(CDC* pDC, ESplitType nType, const CRect& rectArg);
void RefreshSplitBars(void);
void CSplitterWndEx::OnDrawSplitter(CDC* pDC,
ESplitType nType, const CRect& rectArg)
{
int x_ActivePane, y_ActivePane;
COLORREF hilightcolor = RGB(255,255,0);
GetActivePane(x_ActivePane, y_ActivePane);
if( ((GetRowCount()>1) ||(GetColumnCount()>1))
&& (nType == splitBorder))
{
int pRow = 0;
int pCol = 0;
if(rectArg.top)
{
pRow = 1;
}
if(rectArg.left)
{
pCol = 1;
}
if((pCol == y_ActivePane) && (pRow == x_ActivePane))
{
if (pDC == NULL)
{
RedrawWindow(rectArg, NULL, RDW_INVALIDATE|RDW_NOCHILDREN);
return;
}
ASSERT_VALID(pDC);
CRect rect = rectArg;pDC->Draw3dRect(rect,
hilightcolor, hilightcolor);
int dx = -GetSystemMetrics(SM_CXBORDER);
int dy = -GetSystemMetrics(SM_CYBORDER);
rect.InflateRect(dx,dy);
pDC->Draw3dRect(rect, hilightcolor, hilightcolor);
return;
}
}
CSplitterWnd::OnDrawSplitter(pDC,nType,rectArg);
}
This method draws an extra Rectangle
around the ActivePane
with the color hilightcolor
.
Note: You can set 2 colors (see help for Draw3dRect
).
void CSplitterWndEx::RefreshSplitBars(void)
{
CRect rectInside;
GetInsideRect(rectInside);
DrawAllSplitBars(NULL, rectInside.right, rectInside.bottom);
}
This method calls the refresh for the splitbars.
You have all your methods to draw the focus window. You just need to call them:
Select Split in the Window menu. When you click a pane, a yellow border is drawn. It shows which pane has the focus.
Automatic Splitting
The Automatic-Splitting is the capability to split a view in 4 views, but without mouse event. It means that the CView
is split into 4 views where newWidth = oldWidth / 2
and newHeight = oldHeight / 2
.
First, add to the CSplitterWnd
class 2 booleans:
Public:
bool m_bSplittingDone;
protected :
bool m_bIsAutomaticSplit;
In the constructor, initialize these members:
CSplitterWndEx::CSplitterWndEx()
{
m_bIsAutomaticSplit = false;
m_bSplittingDone = false;
}
To call the splitting function, you need to use CSplitterWnd::DoKeyboardSplit();
.
We write 4 new methods to the class:
public:
BOOL DoAutomaticSplit();
BOOL DoKeyboardSplit();
protected:
void StartTracking(int ht);
void StopTracking(BOOL bAccept);
void CSplitterWndEx::StartTracking(int ht)
{
HCURSOR theCurrentCursor = GetCursor();
CSplitterWnd::StartTracking(ht);
if ( m_bIsAutomaticSplit )
{
SetCursor(theCurrentCursor);
}
}
void CSplitterWndEx::StopTracking(BOOL bAccept)
{
CSplitterWnd::StopTracking(bAccept);
m_bIsAutomaticSplit = false;
m_bSplittingDone = true;
}
BOOL CSplitterWndEx::DoAutomaticSplit()
{
POINT theInitialMousePosition;
GetCursorPos(&theInitialMousePosition);
m_bSplittingDone = false;
m_bIsAutomaticSplit = true;
BOOL RetVal = CSplitterWnd::DoKeyboardSplit();
SetCursorPos(theInitialMousePosition.x,theInitialMousePosition.y);
return RetVal;
}
BOOL CSplitterWndEx::DoKeyboardSplit()
{
m_bSplittingDone = false;
m_bIsAutomaticSplit = false;
return CSplitterWnd::DoKeyboardSplit();
}
We also need to overload the OnMouseMove
event:
void CSplitterWndEx::OnMouseMove(UINT nFlags, CPoint pt)
{
if ( m_bIsAutomaticSplit )
{
StopTracking(TRUE);
return;
}
CSplitterWnd::OnMouseMove(nFlags,pt);
}
Note, you will need to call the DoAutomaticSplit
method. You can call it in the CChildFrame
class:
void CChildFrame::AutomaticSplit()
{
KillTimer(1);
SetTimer(1, 10 , NULL);
m_wndSplitter.DoAutomaticSplit();
}
void CChildFrame::OnTimer(UINT nIDEvent)
{
if ( m_wndSplitter.m_bSplittingDone )
{
KillTimer(1);
int nbRow = m_wndSplitter.GetRowCount();
int nbCol = m_wndSplitter.GetColumnCount();
for ( int r = 0; r < nbRow ; r++ )
{
for ( int c=0 ; c < nbCol ; c++ )
{
CMyProjView* theView = (CMyProjView*)m_wndSplitter.GetPane(r,c);
if ( r==0 && c== 0)
else if ( r==0 && c== 1)
else if ( r==1 && c== 0)
else if ( r==1 && c== 1)
}
}
}
}
Here, I’m using a trick with a timer to do something when the splitting is done.
Now, you can call the CChildFrame::AutomaticSplit()
method to split the CView
.
For example, with the Class Wizard, you can create a new entry in the Window menu, and add the call to AutomaticSplit
:
void CChildFrame::OnWindowAutomaticsplit()
{
AutomaticSplit();
}
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.