Link to home
Start Free TrialLog in
Avatar of Zainal062797
Zainal062797

asked on

Creating Multiple Views of different types in SDI

I have an SDI application. I am trying to have multiple views of different types (Classes) for the same document. I do not want to use CSplitterWnd since it forces me to have the multiple views within one main window. I would like to have the multiple views in different windows, as if they were child windows of the main windows so I would be able to make them overlap min.mximize, etc.
Please advise.
Thank you.
ASKER CERTIFIED SOLUTION
Avatar of RONSLOW
RONSLOW

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of RONSLOW
RONSLOW

go to

http://www.codeguru.com/doc_view/index.shtml

there are a number of articles there under the "View management" heading, including:

MultiSingle (MSDI) Document interface - Lanz Jean-Claude (1998/08/06)
MultiSingle (MSDI) Document interface with DAO doc - Lanz Jean-Claude (1998/08/06)
Multiple Views Using SDI - Richard Stringer (1998/12/02)
SDI Interface with Multi-Views and Multi-Splitters - Jean-Claude Lanz (1999/02/14)
Switching to other view in a doc-view application - Jorge Lodos (1999/03/02)
Multiple frame windows in SDI application - Ole Lennert (1999/04/03)

Good hunting !!

Do you want functionality like Outlook Express where you double click on the mail message and a new window open with the message?

If yes, then read on.

1. You have to create and maintain a pointer list of the windows. You should add FrameWnd pointer to the list when ever you open a new window and remove it is closed.
2. To create a new window, call CreateNewFrame(...).

These are two basic functionality you have to implement. Rest is not much. Feel free to ask if you have more queries.

All the best.

Vicky
Take a look at this article from Microsoft Knowledge Base.
http://support.microsoft.com/support/kb/articles/Q100/9/93.ASP

To get this article by mail, send a blank mail to mshelp@microsoft.com with Q100993 in the subject line.

Vicky
Avatar of Zainal062797

ASKER

Thank you for your advice V_Bapat. However, I am using SDI, and when I try to create the second view, the program crashes. It seems like your solution works only for MDI. Please let me know if there is a way around this.

Thank you.
Did you check out the examples at codeguru? They all give SDI with multiple views.
You can have multiple views in a SDI application. Create the other
views separately by inserting a new class. Make sure that this class is
derived from the appropriate view class. Assume that this view is called
CMyNewView.

Add the following protected instance variable and member function
in the CMainFrame class.

protected:
enum show {MYVIEW=1, DEFVIEW=2};
void SwitchView(show nView);

Add the following menu option : MyView  (mapped to OnMyView) and
DefaultView (mapped to OnDefView)

Write the following code for OnMyView
void CMainFrame::OnMyView()
{
// TODO: Add your command handler code here
SwitchView(MYVIEW);
}

Similarly this code goes for OnDefView
void CMainFrame::OnDefView()
{
// TODO: Add your command handler code here
SwitchView(DEFVIEW);
}

Here is the code for SwitchView
void CMainFrame::SwitchView(show nView){
CView * poldview=GetActiveView();
CView * pnewview=(CView *)GetDlgItem(nView);
if(pnewview==NULL){
switch(nView){
case MYVIEW:
pnewview=(CView *)new CMyNewView;
break;
case DEFVIEW:
pnewview=(CView *)new CMyAppView;
break;
}
CCreateContext context;
context.m_pCurrentDoc=poldview->GetDocument();
pnewview->Create(NULL,NULL,0L,CFrameWnd::rectDefault,this,nView,&context);
pnewview->OnInitialUpdate();
}
SetActiveView(pnewview);
pnewview->ShowWindow(SW_SHOW);
poldview->ShowWindow(SW_HIDE);
poldview->SetDlgCtrlID(poldview->GetRuntimeClass()==
RUNTIME_CLASS(CMyAppView)?DEFVIEW:MYVIEW);
pnewview->SetDlgCtrlID(AFX_IDW_PANE_FIRST);
RecalcLayout();
}

Also add these handlers:
void CMainFrame::OnUpdateViewDefView(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(!GetActiveView()->IsKindOf(RUNTIME_CLASS(CMyAppView)));
}

void CMainFrame::OnUpdateViewMyNewView(CCmdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(!GetActiveView()->IsKindOf(RUNTIME_CLASS(CMyNewView)));
}

Hope this helps
pagladasu

The above has one view window and simply changes the type of view displayed in that window.  This is not what is wanted (from what I understand of the question).

I have a more generalised method for this in my apps ... you only need to change (or add) a line for each view type to have as many views as you want.

My example works within a splitter, which is not in the specs of this app, but thought someone may find it useful.  It allows you to change the type of view in each splitter pane.

One day I'll add a lookup table from ID to runtime class to make it truly extensible and stick it in my utility library .. but here it is (a bit different from the above - mainly because of splitter support):

void CMainFrame::OnViewSelect(UINT id) {
  // work out the type of view required
  // from the ID given
  CRuntimeClass* pViewClass = NULL;
  switch (id) {
  // add to and/or change these lines
  // for additional classes
  case ID_VIEW_1: pViewClass = RUNTIME_CLASS(CView1); break;
  case ID_VIEW_2: pViewClass = RUNTIME_CLASS(CView2); break;
  }
  // don't know what class to create
  if (! pViewClass) return;
  // Get pointer to CDocument object so
  // that it can be used in the
  // creation process of the new view
  CDocument* pDoc = GetActiveDocument();
  if (! pDoc) return;
  // if no old view, then cannot change
  CView* pOldView = GetActiveView();
  if (! pOldView) return;
  // get pointer to splitter (parent)
  // must be
  CSplitterWnd* pSplitter = static_cast<CSplitterWnd*>(pOldView->GetParent());
  if (! pSplitter || ! pSplitter->IsKindOf(RUNTIME_CLASS(CSplitterWnd))) return;
  // find which pane
  int row,col;
  if (pSplitter->IsChildPane(pOldView,&row,&col)) {
    int w,h,minw,minh;
    pSplitter->GetColumnInfo(col,w,minw);
    pSplitter->GetRowInfo(row,h,minh);
    // set flag so that document will
    // not be deleted when view is
    // destroyed
    {
      BOOL bAutoDelete = pDoc->m_bAutoDelete;
      pDoc->m_bAutoDelete=false;    
      pOldView->DestroyWindow();
      pDoc->m_bAutoDelete=bAutoDelete;
    }
    // Create new view
    CCreateContext context;
    context.m_pNewViewClass=pViewClass;
    context.m_pCurrentDoc=pDoc;
    context.m_pNewDocTemplate=NULL;
    context.m_pLastView=NULL;
    context.m_pCurrentFrame=NULL;
    if (! pSplitter->CreateView(row,col,pViewClass,CSize(w,h),&context)) {
      ::AfxMessageBox("Could not create view");
    } else {
      CView* pNewView = static_cast<CView*>(pSplitter->GetPane(row,col));
      SetActiveView(pNewView);
      pNewView->SendMessage(WM_INITIALUPDATE,0,0);
      pSplitter->SetColumnInfo(col,w,minw);
      pSplitter->SetRowInfo(row,h,minh);
      pSplitter->RecalcLayout();
      pNewView->UpdateWindow();
    }
  }
}
Zainal:
>> It seems like your solution works only for MDI.

It is for SDI. What I missed out in my last post is that you have to create a DocTemplate.
I am using this method in my Project. This is a snippet from my CWinApp derived class.

      // Register the application's document templates.  Document templates
      //  serve as the connection between documents, frame windows and views.

// DocTemplate created by AppWizard

      CSingleDocTemplate* pDocTemplate;
      pDocTemplate = new CSingleDocTemplate(
            IDR_MAINFRAME,
            RUNTIME_CLASS(CNetpowerDoc),
            RUNTIME_CLASS(CNetpowerFrameWnd),       // main SDI frame window
            RUNTIME_CLASS(CNetpowerView));
      AddDocTemplate(pDocTemplate);

      {
            // BLOCK: doc template registration
            // Register the document template.  Document templates serve
            // as the connection between documents, frame windows and views.
            // Attach this form to another document or frame window by changing
            // the document or frame class in the constructor below.
            m_pPolicyEditorDocTemplate = new CSingleDocTemplate(
                  IDR_CHILDFRAME,
                  RUNTIME_CLASS(CPolicyEditorDoc),              // Document class
                  RUNTIME_CLASS(CPolicyEditorFrm),          // Child frame class
                  RUNTIME_CLASS(CPolicyEditorView));       // View class
            AddDocTemplate(m_pPolicyEditorDocTemplate);
      }

You have to create document, view and frame window classes derived from CDocument, CView(or what your requirement is) and CFrameWnd respectively.

It is a bit complicated and to understand it properly, you have to understand what and how CDocManager(undocumented class) class works.


Vicky
Did you check out the examples at codeguru?

They all give SDI with multiple views.

Please check them out and let me know what you think.