Switching between different ribbons in an MDI application - c++

I'd like to switch between different ribbons for different MDI child frames in my application. I know it's possible with the old style menus, but I can't get it working with the feature pack ribbons.
The code used when it's old style menus:
pDocTemplate = new CMultiDocTemplate(
IDR_MAINFRAME,//Menu to load
RUNTIME_CLASS(CModDoc),
RUNTIME_CLASS(CModFrame), // custom MDI child frame
RUNTIME_CLASS(CdotView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
pDocTemplate = new CMultiDocTemplate(
IDR_RES_RNGACTIV,//Menu to load
RUNTIME_CLASS(CModRangeDoc),
RUNTIME_CLASS(CModRangeFrame), //custom MDI child frame
RUNTIME_CLASS(CBlankView));
if (!pDocTemplate)
return FALSE;
AddDocTemplate(pDocTemplate);
Another approach I'm thinking of is to unload the current Ribbon and load a new Ribbon from resources?
//Unload ribbon code?
m_wndRibbonBar.LoadFromResource(IDR_RIBBON);

there is no need to have multiple CMFCRibbonBar objects if you don't need to, you can just use the CMFCRibbonBar::LoadFromResource and then you will have to use the CMFCRibbonBar::RecalcLayout method to apply the changes to the User Interface.
Remember to check the return value of CMFCRibbonBar::LoadFromResource to be sure that the load was successful, and it is really important that you call the CMFCRibbonBar::RecalcLayout otherwise you will not see the new ribbon.

I ended up hiding the original ribbonbar and then loading and displaying a new one. Not sure if it's the best way to do it though.
CMultiDocTemplate *pDoc = GetDocTemplate(7);
if (pDoc)
{
CFloorActivDoc* pDocument = (CFloorActivDoc*)pDoc->CreateNewDocument();
CFloorFrame* pFrame = (CFloorFrame*)pDoc->CreateNewFrame(pDocument, NULL);
if (pFrame)
{
pDoc->InitialUpdateFrame(pFrame, pDocument);
m_wndRibbonBar.ShowPane(FALSE, FALSE, TRUE);//Hide original ribbon
m_FloorRibbonBar.Create(this);
m_FloorRibbonBar.LoadFromResource(IDR_RIBBON_FLOORACT);
}

Related

Reset Layout of CDockablePane

I migrated my MFC MDI application to use the new MFC Feature Pack. I have many toolbars and dockable panes. As far as I understand, the location and size of each of them is saved in the registry when closing the application, and loaded when loading the main frame.
I want to add a feature in my application to reset the layout of the toolbars/panes to the original layout.
I have tabbedpanes also in my application.
sometimes I will dock separate panes to tabbed panes.
Is there a way to actually reset the layout of my application AFTER it has been loaded?
Visual Studio has a similar feature called "Reset Window Layout".
I am getting samples in the internet for restoring mainframe window using SetWindowPlacement() and GetWindowPlacement().
I don't know how to use these functions for toolbars and CDockablePanes and achieve my requirement?
Is there any other solution apart from using SetWindowPlacement() and GetWindowPlacement()?
I am able to meet my requirement using below code.
void CMainFrame::OnPanesResetLayout()
{
CDockingManager* pDockMgr = GetDockingManager();
if (pDockMgr == NULL)return;
CRect rect;
rect.SetRectEmpty();
ClientToScreen(rect);
SetRedraw(FALSE);
CObList list;
pDockMgr->GetPaneList(list, TRUE,0,TRUE);
// UnDock and hide DockingControlBars
POSITION pos;
for (pos = list.GetHeadPosition(); pos != NULL;)
{
CBasePane* pBarNext = (CBasePane*) list.GetNext(pos);
if (!::IsWindow(pBarNext->m_hWnd))continue;
CDockablePane* pBar = DYNAMIC_DOWNCAST(CDockablePane, pBarNext);
if (pBar != NULL)
{
if(pBar->IsAutoHideMode()) pBar->SetAutoHideMode(FALSE, CBRS_ALIGN_ANY);/*ToggleAutoHide();*/
if (pBar->IsMDITabbed ())
continue;
pBar->UndockPane();
ShowPane(pBar, FALSE,FALSE, FALSE);
}
CMFCToolbar* pToolBar = DYNAMIC_DOWNCAST(CMFCToolbar, pBarNext);
if(pToolBar)
pToolBar->m_recentDockInfo.m_recentSliderInfo.m_rectDockedRect = rect;
}
m_wndBar1.DockToFrameWindow(CBRS_LEFT,m_wndBar1.GetAHRestoredRect());
ShowPane(m_wndBar1, TRUE,FALSE, FALSE);
m_wndBar2.DockToFrameWindow(CBRS_RIGHT,m_wndBar2.GetAHRestoredRect());
ShowPane(m_wndBar2, TRUE,FALSE, FALSE);
//for tabbed pane
CTabbedPane *pTabbedPane;
m_wndTab1.DockToFrameWindow(CBRS_BOTTOM,m_wndTab1.GetAHRestoredRect());
m_wndTab2.AttachToTabWnd(&m_wndTab1, DM_SHOW, FALSE,reinterpret_cast<CDockablePane**>(&pTabbedPane));
m_wndTab3.AttachToTabWnd(&m_wndTab1, DM_SHOW, FALSE,reinterpret_cast<CDockablePane**>(&pTabbedPane));
ShowPane(m_wndTab1, TRUE,FALSE, FALSE);
ShowPane(m_wndTab2, TRUE,FALSE, FALSE);
ShowPane(m_wndTab3, TRUE,FALSE, FALSE);
SetRedraw(TRUE);
RedrawWindow(NULL, NULL, RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE | RDW_ALLCHILDREN);
AdjustClientArea();
}
As described in my comment above, one option to restore the initial layout from a running application would be to use the methods provided by CDockablePane, specifically
AttachToTabWindow
DockToWindow and
ShowPane
A second option, which would require restarting your application, is to call EnableLoadDockState(FALSE) in the constructor of your CFrameWndEx derived class. This would prevent loading the stored dock state and, as a consequence, restore the initial layout.
A simple method to solve this is to delete from registry key all keys which store the panels info: "BasePane" and "Pane" from "Workspace" registry folder from your app registry entry :) Easy.

Create a ListView in MFC without having dialogs

I am trying to create a ListView in MFC C++ in my Child window. I have just finished reading this article on CodeProject. I recommend it to anyone who wants to create the control in a dialog or that has created it already and tries to learn more about it.
Here comes my question! I have to create the ListView control at ::OnCreate() of my ChildWindow. How can I do this?
Here is what I've tried so far:
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIChildWnd::OnCreate(lpCreateStruct) == -1)
return -1;
CListCtrl *CarsListView = new CListCtrl();
CarsListView->SetView(LVS_REPORT);
CarsListView->ShowWindow(SW_SHOW);
return 0;
}
(code that is obviously not working...)
There is no Need to use new to create a list view object.
Creating the object doesn't create the window. You Need to call CListView::Create
Maybe you should read a MFC tutorial...

C++ MFC MDI how to change what class view displays based on active document

I'm working on an MDI application that has an object browser (CClassView) that has to change what it displays based on what "document" is active.
PS: None of my searches have worked.
This isn't what I expected, but here's a possible solution:
http://forums.codeguru.com/showthread.php?473808-MFC-Doc-View-How-to-get-the-active-document-anywhere-in-my-application
Q: How to get the active document anywhere in my application?
A: There are several methods, one is to get first the active frame
then call CFrameWnd::GetActiveDocument. ... In MDI applications, we
have to additionally get the active MDI child frame.
CDocument* GetMDIActiveDocument()
{
CDocument* pDoc = NULL;
CWnd* pWndMain = AfxGetMainWnd();
ASSERT(pWndMain);
ASSERT(pWndMain->IsKindOf(RUNTIME_CLASS(CMDIFrameWnd))); // Not an MDI app.
CFrameWnd* pFrame = ((CMDIFrameWnd*)pWndMain)->MDIGetActive();
if(NULL != pFrame)
{
pDoc = pFrame->GetActiveDocument(); // get the active document
}
return pDoc;
}
This sample code might suggest other (perhaps even better) alternatives:
http://msdn.microsoft.com/en-us/library/cstcs513%28v=vs.90%29.aspx

How to close a MFC CVIEW while keeping the document open

I have a MFC CDocument and associated CView open in a MDI application. I would like to detach and close the view (and associated frame), while keeping the document open. Looking around the MFC code to see how it does it, reveals the following in CDocument::OnCloseDocument();
// destroy all frames viewing this document
// the last destroy may destroy us
BOOL bAutoDelete = m_bAutoDelete;
m_bAutoDelete = FALSE; // don't destroy document while closing views
while (!m_viewList.IsEmpty())
{
// get frame attached to the view
CView* pView = (CView*)m_viewList.GetHead();
ASSERT_VALID(pView);
CFrameWnd* pFrame = pView->EnsureParentFrame();
// and close it
PreCloseFrame(pFrame);
pFrame->DestroyWindow();
// will destroy the view as well
}
m_bAutoDelete = bAutoDelete;
which I guess I could use in conjunction with CDocument::RemoveView. Is there a better way to approach this than just lifting the MFC source, and is this approach going to cause me other problems or side effects? The project is VS2010 C++.
If you set CDocument::m_bAutoDelete to FALSE (after the document has been created) it should not delete the document when the last view closes.
I'm not sure what you're specifically trying to do but you might want to consider creating a separate 'data' object that can be attached to a document rather than trying to keep the document itself around.

Configuring new document in MFC

When the user creates a new document in my SDI-application, I need to present a dialog specifying details on the document to be created (think: resolution, bit-depth, etc.) I initially put the code for displaying this dialog in OnNewDocument() (I don't need it when opening an existing document), but putting user-interface code in the document-class just doesn't feel right (also, I don't have any CWnd* to use as a parent for the dialog).
Is there a better place to do this in MFC?
You're right, the document class is no good place for UI.
CDocTemplate::[OpenDocumentFile][1](pszPath) looks like a better candidate:
pszPath==NULL means 'create a new document'.
The method is virtual -> Just derive CMySingleDocTemplate from CSingleDocTemplate and use an instance of this class in CMyWinApp::InitInstance().
This class is responsible for creating docs, frames and views, hence I think it's a good place to put a UI operation.
BOOL CMyWinApp::InitInstance()
{
...
CSingleDocTemplate* pDocTemplate;
pDocTemplate = new CMySingleDocTemplate( // <--Derives from CSingleDocTemplate
IDR_MAINFRAME,
RUNTIME_CLASS(CMyDoc),
RUNTIME_CLASS(CMainFrame),
RUNTIME_CLASS(CMyView));
AddDocTemplate(pDocTemplate);
...
}
CDocument* CMySingleDocTemplate::OpenDocumentFile(LPCTSTR lpszPathName,
BOOL bMakeVisible)
{
CDocument *pDoc =
CSingleDocTemplate::OpenDocumentFile(lpszPathName, bMakeVisible);
if (lpszPathName==NULL)
{
// GUI to get user info
// update doc
m_pOnlyDoc->Blah(input);
// update view
m_pOnlyDoc->UpdateAllViews(NULL,...,...);
}
}
This might not be ideal though: In SDI, there is one and only doc object. It's re-used accross File/Load and File/New operation.
This function will then be called a first time before the initial mainframe is created. You may not want to have a dialog presented to user before the frame is created. Ouch! It's a little more complicated:
Instead of popping up a GUI in in OpenDocumentFile(NULL) as above, just post a custom message/command to the main frame. Then add a handler that will react by the sequence pop up GUI/update doc/update views. That way, the main frame will be displayed before the GUI is popped up and your user will be happier.
This also solves your problem where you don't have a CWnd parent: the main frame is already created and your dialog will use it byt default.
BTW, another solution consists in adding a command handler for ID_FILE_NEW in your CMyWinApp's message map and add your own override of OnFileNew(). But when you write OnFileNew(), I believe you'll quickly find out that it's an ugly solution :-(