Solved

Changing views in CSplitterWnd

Posted on 1998-12-20
6
2,199 Views
Last Modified: 2013-11-20
IN my app (SDI MFC app), I've got a splitter wnd with 2 views, left and right. The right view has got another splitter with 2 views, top and bottom. How can I switch the top or bottom view to other CFormView derived views, depending on menu items selected by the user? Left and right views are derived from CView. Top and bottom views are derived from CFormView.

// Create left and right view in CMainFrame

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT lpcs, CCreateContext* pContext)
{
      if (!m_wndSplitter.CreateStatic(this,1,2))
      {
            TRACE0("Failed to create left-right splitter window\n");
            return FALSE;
      }

      if (!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CViewLeft),CSize(58,0),pContext))
      {
            TRACE0("Failed to create left view\n");
            return FALSE;
      }
      if (!m_wndSplitter.CreateView(0,1,RUNTIME_CLASS(CViewRight),CSize(0,0),pContext))
      {
            TRACE0("Failed to create right view\n");
            return FALSE;
      }
      return TRUE;
}

// Create top and bottom views in CRightView

int CViewRight::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
        pContext = (CCreateContext *)lpCreateStruct->lpCreateParams;
      
      if (CView::OnCreate(lpCreateStruct) == -1)
            return -1;
      
      if (!m_wndSplitter.CreateStatic(this,2,1))
      {
            TRACE0("Failed to create the top-bottom splitter window\n");
            return FALSE;
      }
      else
      {
            if (!m_wndSplitter.CreateView(0,0,RUNTIME_CLASS(CFormTop),CSize(0,130),pContext)) return FALSE;
            if (!m_wndSplitter.CreateView(1,0,RUNTIME_CLASS(CFormBottom),CSize(0,0),pContext)) return FALSE;

            m_wndSplitter.RecalcLayout();
            m_wndSplitter.SetActivePane(1,0);
      }
      return 0;
}
0
Comment
Question by:k9
6 Comments
 
LVL 12

Expert Comment

by:migel
ID: 1326455
Hi! I think you must derive your own class from CSplitterWnd and add some functionality to manipulate splitter panes.
for example:
class CMySplitter:public CSplitterWnd
{
public:
BOOL SubstitutePane(int row, int col, CRuntimeClass* pRuntime)
}

BOOL CMySplitter::SubstitutePane(int row, int col, CRuntimeClass* pRuntime)
{
int cxCur, cyCur, cxMin, cyMin;
GetRowInfo(row, cyCur, cyMin) ;
GetColumnInfo(col, cxCur, cxMin);
DeleteView(row,col);
CSize sz(cxCur, cyCur);
if (!CreateView(row, col, pRuntime, sz, NULL))
    return FALSE
RecalcLayout();
}
0
 

Author Comment

by:k9
ID: 1326456
Thanks for getting back to me. Have previously tried DeleteView and CreateView to switch views. Proggie keeps falling over using above method. DeleteView works (proggie does not complain), but falls over as soon as you try CreateView for new view.

---------------------------------------------------------------
For interest:

Found different way from Ken C Len on http://www.codeguru.com

Create static splitter in CMainFrame as above. Derive CRightView from CFrameWnd. Create different CView/CFormView derived classes and create all views to be used in app in CRightView::OnCreateClient. Use ShowWindow(SW_SHOW) and ShowWindow(SW_HIDE) to hide and display views as needed. Couple of bugs in this implementation with CFormView derived classes.
0
 
LVL 12

Expert Comment

by:migel
ID: 1326457
Ok. This way works only for static splitter not dynamic, due to splitter does not store pointers to the panes (he works with window child ID calculated from pane`s row and col).
I think to implement this way to the dynamic view you must dynamically change panes ID by ::SetWindowLong(pPane->m_hWnd, GWL_ID, uValue);
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 12

Expert Comment

by:migel
ID: 1326458
Can you send me sample code (to migel@geocities.com) I try to resolve problem
0
 
LVL 2

Expert Comment

by:wyy_cq
ID: 1326459
in this case ,
i recommend you write some extra code to implement the splitterBar and treat the two views as child.

if you work with Doc Templete change the view will be very hard.

0
 
LVL 1

Accepted Solution

by:
appdev earned 400 total points
ID: 1326460
  This is a question that I answered recently...
Maybe, this is the way that you want to change the panes.
You can derive one class from CSplitterWnd.
This is the implementation file :

// Splitter.cpp : implementation file
//

#include "stdafx.h"              
#include "colf.h"

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

/////////////////////////////////////////////////////////////////////////////
// CSplitter

IMPLEMENT_DYNCREATE(CSplitter, CSplitterWnd)

CSplitter::CSplitter()
{
}

CSplitter::~CSplitter()
{
}



BEGIN_MESSAGE_MAP(CSplitter, CSplitterWnd)
//{{AFX_MSG_MAP(CSplitter)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CSplitter message handlers


BOOL CSplitter::ReplaceView(int row, int col, CRuntimeClass* pViewClass, SIZE size)
{
  CCreateContext context;
  BOOL bSetActive;
       
   
  //if ((GetPane(row,col)->IsKindOf(pViewClass))==TRUE)
    //   return FALSE;
     
   
   // Get pointer to CDocument object so that it can be used in the creation
   // process of the new view
   CDocument * pDoc= ((CView *)GetPane(0,0))->GetDocument();
   CView * pActiveView=GetParentFrame()->GetActiveView();
   if (pActiveView==NULL || pActiveView==GetPane(row,col))
      bSetActive=TRUE;
   else
      bSetActive=FALSE;

    // set flag so that document will not be deleted when view is destroyed
pDoc->m_bAutoDelete=FALSE;    
    // Delete existing view
   ((CView *) GetPane(row,col))->DestroyWindow();
    // set flag back to default
    pDoc->m_bAutoDelete=TRUE;
 
    // Create new view                      
   
   context.m_pNewViewClass=pViewClass;
   context.m_pCurrentDoc=pDoc;
   context.m_pNewDocTemplate=NULL;
   context.m_pLastView=NULL;
   context.m_pCurrentFrame=NULL;
   
   CreateView(row,col,pViewClass,size, &context);
   
   CView * pNewView= (CView *)GetPane(row,col);
   
   if (bSetActive==TRUE)
      GetParentFrame()->SetActiveView(pNewView);
   
   RecalcLayout();
   GetPane(row,col)->SendMessage(WM_PAINT);
   
   return TRUE;
}


   And this is the header file :


// Splitter.h : header file
//

/////////////////////////////////////////////////////////////////////////////
// CSplitter frame with splitter

#ifndef __AFXEXT_H__
#include <afxext.h>
#endif

class CSplitter : public CSplitterWnd
{
DECLARE_DYNCREATE(CSplitter)
public: //protected:
CSplitter();           // protected constructor used by dynamic creation

// Attributes
public:

// Operations
public:
BOOL ReplaceView(int row, int col, CRuntimeClass* pViewClass, SIZE size);

// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSplitter)
//}}AFX_VIRTUAL

// Implementation
public:
virtual ~CSplitter();

// Generated message map functions
//{{AFX_MSG(CSplitter)
// NOTE - the ClassWizard will add and remove member functions here.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};

/////////////////////////////////////////////////////////////////////////////


   Now, in your mainframe class add a member variable, this way :

CSplitter m_wndSplitter;

   Add the WM_CREATE message in the Class Wizard.    

BOOL CMainFrame::OnCreateClient(LPCREATESTRUCT /*lpcs*/,
CCreateContext* pContext)
{
// create splitter window
if (!m_wndSplitter.CreateStatic(this, 2, 1))
return FALSE;

if (!m_wndSplitter.CreateView(0, 0, RUNTIME_CLASS(CMyUpView), CSize(200, 100), pContext) ||
!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CMyDownView), CSize(50, 50), pContext))
{
m_wndSplitter.DestroyWindow();
return FALSE;
}

return TRUE;
}

   You can change any view when you want it...
e.g. when the user double click on your View...

CMyUpView::OnDblclk(NMHDR* pNMHDR, LRESULT* pResult)
{
   ...maybe code to check the place (coordinates, item, etc) of the double click...

   SIZE size;
   size.cx=100;
   size.cy=100;
   ((CSplitter *)GetParent())->ReplaceView(1,0,RUNTIME_CLASS(CMyDownView), size);
   ...or...
    ((CSplitter *)GetParent())->ReplaceView(1,0,RUNTIME_CLASS(CBlankView), size);


}

Hope this help you.
Salvador.

0

Featured Post

Announcing the Most Valuable Experts of 2016

MVEs are more concerned with the satisfaction of those they help than with the considerable points they can earn. They are the types of people you feel privileged to call colleagues. Join us in honoring this amazing group of Experts.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Suggested Solutions

Title # Comments Views Activity
notReplace  challenge 53 141
bigDiff challenge 17 124
zeroMAx challenge 20 111
fix34  challenge 9 141
In this article, I'll describe -- and show pictures of -- some of the significant additions that have been made available to programmers in the MFC Feature Pack for Visual C++ 2008.  These same feature are in the MFC libraries that come with Visual …
Introduction: Displaying information on the statusbar.   Continuing from the third article about sudoku.   Open the project in visual studio. Status bar – let’s display the timestamp there.  We need to get the timestamp from the document s…
This video will show you how to get GIT to work in Eclipse.   It will walk you through how to install the EGit plugin in eclipse and how to checkout an existing repository.
With Secure Portal Encryption, the recipient is sent a link to their email address directing them to the email laundry delivery page. From there, the recipient will be required to enter a user name and password to enter the page. Once the recipient …

856 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question