1

I have an MFC program written that reads files, stores the data, and draws it as text on the client view.

I want to make a menu button View->Split that splits the client area into two, separately scrolling views displaying the same data.

I saw some things about CWndSplitter online and read through some documentation but none of it has proved to be useful because they talk about using OnCreate and deleting the default view to get it to work. This is not an option. I want to keep the default view, but split it in two if the user clicks the button.

I've currently created a CWndSplitter member variable and defined a menu button event handler in my SDI-1View.cpp. When called, it does absolutely nothing but cause the screen to flicker and a second click crashes the program.

void CSDI1View::OnViewSplit32778()
{
// TODO: Add your command handler code here

/*
int rows = 2;
int columns = 1;
if (!m_wndSplitter.CreateStatic(this, rows, columns))
    return;

if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CSDI1View), CSize(100, 100), NULL) ||
    (!m_wndSplitter.CreateView(1, 0, RUNTIME_CLASS(CSDI1View), CSize(100, 100), NULL)))
{
    m_wndSplitter.DestroyWindow();
    return;
}
*/
}

Can anyone tell me what the normal approach to splitting a client view in half is? I just want to integrate that into an event handler. Any help would be greatly appreciated.

Thanks.

--------------------------------EDIT----------------------------------

I now have the following code in my Split button event handler, thanks to the outline provided by xMRi, but it is still not working properly...

void CMainFrame::OnViewSplit()
{
// TODO: Add your command handler code here
//calculate client size 
CRect cr;
GetClientRect(&cr);

if (!m_mainSplitter.CreateStatic(this, 2, 1))
{
    MessageBox(_T("Error setting up splitter frames! (CreateStatic)"),
        _T("Init Error!"), MB_OK | MB_ICONERROR);
    return;
}

// Set the parent of the splitter window to the current view
CSDI1View * view = CSDI1View::GetView();
m_mainSplitter.SetParent(this);
view->SetParent(&m_mainSplitter);

// Create a CCreateContext
CCreateContext cc;
CRuntimeClass* prt = RUNTIME_CLASS(CSDI1View);
cc.m_pNewViewClass = prt;
cc.m_pCurrentDoc = view->GetDocument();
cc.m_pNewDocTemplate = NULL;
cc.m_pLastView = NULL;
cc.m_pCurrentFrame = this;

if (!m_mainSplitter.CreateView(0, 0,
    cc.m_pNewViewClass,
    CSize(cr.Width(), cr.Height()/2), &cc))
{
    MessageBox(_T("Error setting up splitter frames! (CreateView 1)"),
        _T("Init Error!"), MB_OK | MB_ICONERROR);
    return;
}

if (!m_mainSplitter.CreateView(1, 0,
    cc.m_pNewViewClass,
    CSize(cr.Width(), cr.Height()/2), &cc))
{
    MessageBox(_T("Error setting up splitter frames! (CreateView 2)"),
        _T("Init Error!"), MB_OK | MB_ICONERROR);
    return;
}

m_bInitSplitter = TRUE;
}

Upon clicking the view->split button, I get a "Debug Assertion Error" popup and the first call to CreateView returns FALSE, displaying my messagebox: "Error setting up splitter frames! (CreateView 1)"

JayB
  • 397
  • 6
  • 21

2 Answers2

3

A static splitter is for a static split--i.e., a window that's always split. You usually use it when you want to have a different view in each pane of the split (e.g. display a column of numbers in one pane, and a graph in the other pane).

For a situation like yours that you want to be able to have the window, then later split it and have two essentially identical views, you (at least normally) want to use a dynamic splitter.

At least normally, you create the splitter when you create the view. That will create a window that has a handle at the top, right-hand corner that the user pulls down to split the view:

enter image description here

To split the window, the user pulls down on the handle:

enter image description here

When the split is where they want it, they release the mouse button, and the view splits into two separately scrollable sections:

enter image description here

Since you didn't specify whether you wanted vertical or horizontal splitting, I set this one up to allow either or both:

enter image description here

The code for this looks something like this:

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT, CCreateContext* pContext) {
    return my_splitter.Create(this,
        2, 2,               // 2 rows, 2 columns
        CSize(20, 20),      // minimum pane size
        pContext);
}

where my_splitter is defined something like this:

CSplitterWnd my_splitter;
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Thanks for this. I want to create a static split that I can essentially turn on and off by switching the parents around, essentially what xMRi has described in his answer. I've run into another problem though, please see my question edit. – JayB Nov 21 '14 at 15:30
1

If you want to use a splitter window on demand, you need to change the parent of the current view. So the steps are:

  • create a simple SDI application
  • On demand create a splitter window
  • Use SetParent to the current view and set it as a parent in the splitter window.
  • Create another window in the second splitter.

And the way back.

  • Use SetParent and attach the normal view back to the main frame.
  • Destroy the splitter

There are active samples how to switch a view in a current document (MSDN). It helps you how IDs must be replaced and changed.

xMRi
  • 14,982
  • 3
  • 26
  • 59
  • Thanks for the breakdown, this exactly what I was looking for! – JayB Nov 21 '14 at 14:48
  • just to clarify, when you say "Create another window in the second splitter," do you mean in the second window (which is the splitter) or should I be creating two splitters? – JayB Nov 21 '14 at 14:49
  • No! My answer regards to a splitter with two different kind of view. So creating means to create the second view that should be shown in the splitter. – xMRi Nov 21 '14 at 15:56
  • Ok. I've followed your steps to create a splitter and posted my updated code in my question, it still doesn't seem to be working. Maybe you can take a look and see if you can find what I've done wrong? Thanks. – JayB Nov 21 '14 at 16:32
  • You didn't follw my advise. The splitter has the main frame as it's parent. The view has the splitter as a parent... you set the splitter to be a child of the view and this is wrong. – xMRi Nov 22 '14 at 08:32
  • Ok, I've made this correction but now I'm getting a Debug Assertion Error and the call to CreateView from the CSplitterWnd is returning FALSE – JayB Nov 22 '14 at 21:49
  • I've also setup a CCreateContext (wasn't sure if I should) and specified it in the CreateView call – JayB Nov 22 '14 at 22:26
  • Tell me where you get the ASSERT – xMRi Nov 24 '14 at 09:15