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.
Please advise.
Thank you.
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
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
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
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
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.
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(sho w 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=pold view->GetD ocument();
pnewview->Create(NULL,NULL ,0L,CFrame Wnd::rectD efault,thi s,nView,&c ontext);
pnewview->OnInitialUpdate( );
}
SetActiveView(pnewview);
pnewview->ShowWindow(SW_SH OW);
poldview->ShowWindow(SW_HI DE);
poldview->SetDlgCtrlID(pol dview->Get RuntimeCla ss()==
RUNTIME_CLASS(CMyAppView)? DEFVIEW:MY VIEW);
pnewview->SetDlgCtrlID(AFX _IDW_PANE_ FIRST);
RecalcLayout();
}
Also add these handlers:
void CMainFrame::OnUpdateViewDe fView(CCmd UI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(!GetActiveV iew()->IsK indOf(RUNT IME_CLASS( CMyAppView )));
}
void CMainFrame::OnUpdateViewMy NewView(CC mdUI* pCmdUI)
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(!GetActiveV iew()->IsK indOf(RUNT IME_CLASS( CMyNewView )));
}
Hope this helps
pagladasu
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(sho
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=pold
pnewview->Create(NULL,NULL
pnewview->OnInitialUpdate(
}
SetActiveView(pnewview);
pnewview->ShowWindow(SW_SH
poldview->ShowWindow(SW_HI
poldview->SetDlgCtrlID(pol
RUNTIME_CLASS(CMyAppView)?
pnewview->SetDlgCtrlID(AFX
RecalcLayout();
}
Also add these handlers:
void CMainFrame::OnUpdateViewDe
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(!GetActiveV
}
void CMainFrame::OnUpdateViewMy
{
// TODO: Add your command update UI handler code here
pCmdUI->Enable(!GetActiveV
}
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(U INT 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(RUNTIM E_CLASS(CS plitterWnd ))) return;
// find which pane
int row,col;
if (pSplitter->IsChildPane(pO ldView,&ro w,&col)) {
int w,h,minw,minh;
pSplitter->GetColumnInfo(c ol,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=bAutoD elete;
}
// Create new view
CCreateContext context;
context.m_pNewViewClass=pV iewClass;
context.m_pCurrentDoc=pDoc ;
context.m_pNewDocTemplate= NULL;
context.m_pLastView=NULL;
context.m_pCurrentFrame=NU LL;
if (! pSplitter->CreateView(row, col,pViewC lass,CSize (w,h),&con text)) {
::AfxMessageBox("Could not create view");
} else {
CView* pNewView = static_cast<CView*>(pSplit ter->GetPa ne(row,col ));
SetActiveView(pNewView);
pNewView->SendMessage(WM_I NITIALUPDA TE,0,0);
pSplitter->SetColumnInfo(c ol,w,minw) ;
pSplitter->SetRowInfo(row, h,minh);
pSplitter->RecalcLayout();
pNewView->UpdateWindow();
}
}
}
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(U
// 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*>
if (! pSplitter || ! pSplitter->IsKindOf(RUNTIM
// find which pane
int row,col;
if (pSplitter->IsChildPane(pO
int w,h,minw,minh;
pSplitter->GetColumnInfo(c
pSplitter->GetRowInfo(row,
// 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=bAutoD
}
// Create new view
CCreateContext context;
context.m_pNewViewClass=pV
context.m_pCurrentDoc=pDoc
context.m_pNewDocTemplate=
context.m_pLastView=NULL;
context.m_pCurrentFrame=NU
if (! pSplitter->CreateView(row,
::AfxMessageBox("Could not create view");
} else {
CView* pNewView = static_cast<CView*>(pSplit
SetActiveView(pNewView);
pNewView->SendMessage(WM_I
pSplitter->SetColumnInfo(c
pSplitter->SetRowInfo(row,
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(CNetpowerFra meWnd), // main SDI frame window
RUNTIME_CLASS(CNetpowerVie w));
AddDocTemplate(pDocTemplat e);
{
// 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(CPolicyEdito rDoc), // Document class
RUNTIME_CLASS(CPolicyEdito rFrm), // Child frame class
RUNTIME_CLASS(CPolicyEdito rView)); // View class
AddDocTemplate(m_pPolicyEd itorDocTem plate);
}
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
>> 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(CNetpowerFra
RUNTIME_CLASS(CNetpowerVie
AddDocTemplate(pDocTemplat
{
// 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
IDR_CHILDFRAME,
RUNTIME_CLASS(CPolicyEdito
RUNTIME_CLASS(CPolicyEdito
RUNTIME_CLASS(CPolicyEdito
AddDocTemplate(m_pPolicyEd
}
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.
They all give SDI with multiple views.
Please check them out and let me know what you think.
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 !!