MFC toolbar on top row with right align - c++

By default, MFC toolbar are docked on top row left align. Could anyone please tell me how to dock the MFC toolbar on top row with right align (meaning that all toolbar buttons are align to right on the top row)?

If u just want the tool bar at the right top corner, u can use the below code in CMainFrame
if (!m_wndRSToolBar.CreateEx(this, TTBSTYLE_FLAT, WS_OVERLAPPED | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMI,Rect(700,0,0,0),IDR_MAINFRAME) || !m_wndRSToolBar.LoadToolBar(IDR_MAINFRAME1))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}

Related

MFC Allow use to enable/disable floating toolbar via menu command

Added Update 2 on 3/29/2022
My MFC app has the menubar, toolbar, and status bar all working correctly. I am at the point I'm adding creature features...one that really annoys me is the choice of permanently locking them or allow them to float at runtime...I've looked high and low and I've yet to see an example where a user can allow this feature to be dynamically changed once the app is up and running. The first function is from the app which works correctly. NOTE: I have the items allowing docking commented out as this was my test code..I know that those are the lines that enable or disable docking at run time....-> // enable docking
int CMainFrame::OnCreate(LPCREATESTRUCT pptCreate)
{
CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerVS2005));
if ( -1 == CMDIFrameWndEx::OnCreate(pptCreate) )
return -1;
// create menu bar
if ( !m_wndMenuBar.Create(this) )
return -1;
m_wndMenuBar.SetPaneStyle(m_wndMenuBar.GetPaneStyle() | CBRS_SIZE_DYNAMIC | CBRS_TOOLTIPS | CBRS_FLYBY);
// prevent the menu bar from taking the focus on activation
CMFCPopupMenu::SetForceMenuFocus(FALSE);
// set the visual manager and style based on persisted value
theApp.m_nAppLook = theApp.GetInt(_T("ApplicationLook"), ID_VIEW_APPLOOK_VS_2008);
OnApplicationLook(theApp.m_nAppLook);
// create tool bar
if ( !m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_GRIPPER|CBRS_TOOLTIPS|CBRS_FLYBY|CBRS_SIZE_DYNAMIC) || !m_wndToolBar.LoadToolBar(IDR_MAINFRAME) )
return -1;
// create status bar
if ( !m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(miIndicators, sizeof(miIndicators)/sizeof(UINT)) )
return -1;
// enable docking
//m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY);
//m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
m_wndToolBar.EnableToolTips(TRUE);
EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndMenuBar);
DockPane(&m_wndToolBar);
// enable Visual Studio 2005 style docking window behavior
CDockingManager::SetDockingMode(DT_SMART);
// enable Visual Studio 2005 style docking window auto-hide behavior
EnableAutoHidePanes(CBRS_ALIGN_ANY);
// create docking windows
if (!CreateDockingWindows())
{
TRACE0("Failed to create docking windows\n");
return -1;
}
m_wndOutput.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndOutput);
return 0;
}
So I've created a menu item that toggles a flag to turn "docking" on and off. The variable switches correctly.. but the command execution of turning the dock "3 dots" on the left side of the menubar and toolbar always remain...i.e. never goes from Float to Dock mode and vice versa. The logic of the toggle works as I can see in my debugging status window the entry points of TRUE and FALSE are seen each time I click the menu. So I guess the question is, can these items be dynamically turned from FLOAT to DOCK without destroying the window and trying to reinit it which would be a visual disaster?
void CMainFrame::UserDockingBarsOption()
{
CMainFrame* pMainFrame = (CMainFrame*)AfxGetMainWnd();
pMainFrame->m_wndOutput.AddStringDebugTab(_T("Debug: MainFrame--CMainFrame::UserDockingBarsOption()"));
if (UserDockingFlag == TRUE)
{
m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY);
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
UserDockingFlag = FALSE;
pMainFrame->m_wndOutput.AddStringDebugTab(_T("Debug: MainFrame--Inside True"));
}
else
{
m_wndMenuBar.EnableDocking(FALSE);
m_wndToolBar.EnableDocking(FALSE);
EnableDocking(FALSE);
UserDockingFlag = TRUE;
pMainFrame->m_wndOutput.AddStringDebugTab(_T("Debug: MainFrame--Inside False"));
}
}
Update 1:
So like my other posts, I'm back after a family matter. I revisited this and because I'm using:
CMFCMenuBar m_wndMenuBar;
CMFCToolBar m_wndToolBar;
and the only member I can find is IsFloat as a question, not an execute. So it was mentioned I can float or dock it via:
https://learn.microsoft.com/en-us/cpp/mfc/docking-and-floating-toolbars?view=msvc-160
Every example that I see is done within the OnCreate which does not help me as I can't recall it after it's already the child is already constructed. So my thought was to invalidate the toolbar, destroy the toolbar, recreate the tool bar with the user switch of dock or float, and then reorganize the toolbars. I have "most" of this working except for the actual switch control aspect to rebuild the menu with the user option of floating the toolbar or docking it.
What I did in my property sheet is created two buttons for two seperate functions to see if I can get each piece of this to work. One button is destroy the toolbar, the other button is create i.e. recreate the toobar....and both of those "work".
This is all being done in the MainFrame.cpp for simplicity of the member variables, I may move it later if I can get it working.
There are the two functions:
Destroy Function:
void CMainFrame::OnToolBarDestroy()
{
m_wndToolBar.Invalidate();
m_wndToolBar.DestroyWindow();
RecalcLayout();
//OnToolBarCreate();
//m_wndToolBar.ShowPane(FALSE, FALSE, FALSE); // Hide toolbar
}
Recreate Toolbar outside of OnCreate
int CMainFrame::OnToolBarCreate()
{
// TODO: Add your implementation code here.
if (m_wndToolBar)
{
m_wndOutput.AddStringStatusTab(_T("Error: Icon toolbar is already active, action cancelled"));
m_wndOutput.AddStringDebugTab(_T("Debug: MainFrame--Error: Icon toolbar is already active, action cancelled"));
return -1;
}
// Create ToolBar toolbar
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to Create Dialog ToolBar\n");
return -1;
}
CRect rcClientOld;
CRect rcClientNew;
GetClientRect(rcClientOld);
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0, reposQuery, rcClientNew);
//m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
//DockPane(&m_wndToolBar);
RecalcLayout();
//m_wndToolBar.ShowPane(TRUE, FALSE, FALSE); // Show toolbar
return -1;
}
So what is commented out that would make it "work" assuming following the OnCreate code order up to this point:
//m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
//DockPane(&m_wndToolBar);
What happening is the successful destroy, and successful rebuild of the menu.
What I need for switch control is to either have the line active for floating or commented out for docked which I have also done in OnCreate but since this is for the rebuilt menu, I need this to follow that method switching in or out this line: //m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); ...but when I do....the toolbar gets all garbled up / missing all icons and I have to nuke the registry keys for the workspace to "try again"...
Any ideas on how I can make this work? I feel like I'm This close to getting it...I'm just unsure what I may be missing here to get across he goal line.
Update 2
So I got the toolbar to come out of docked to float with modified code below without restarting the app. But there are issues, it seems to be drawing "ghost" bars underneath. If I double click the 3 dots, it will detach and the bar will float....GREAT! But, it leave a "mirror" behind....if I double click the floating menu, it redocks to the frame.
I know I'm close, I'm just missing a piece to finish this off. I've added the code below and a few screenshots of wha I'm seeing.....the point is I is "working", but I'm missing something...can anyone help?
OnDestroy method updated:
int CMainFrame::OnToolBarDestroy()
{
//if (!m_wndToolBar)
//{
// m_wndOutput.AddStringStatusTab(_T("Error: Icon toolbar is already removed, action cancelled"));
// m_wndOutput.AddStringDebugTab(_T("Debug: MainFrame--Error: Icon toolbar is already removed, action cancelled"));
// return -1;
//}
//m_wndToolBar.Invalidate();
//m_wndMenuBar.DestroyWindow();
m_wndToolBar.DestroyWindow();
//m_wndToolBar.AdjustDockingLayout();
//RecalcLayout();
//OnToolBarCreate();
//return 0;
CRect rcClientOld;
CRect rcClientNew;
GetClientRect(rcClientOld);
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0, reposQuery, rcClientNew);
//m_wndToolBar.ShowPane(FALSE, FALSE, TRUE); // Hide toolbar
RecalcLayout();
return 0;
}
OnCreate method updated:
int CMainFrame::OnToolBarCreate()
{
enter code here// TODO: Add your implementation code here.
if (m_wndToolBar)
{
m_wndOutput.AddStringStatusTab(_T("Error: Icon toolbar is already active, action cancelled"));
m_wndOutput.AddStringDebugTab(_T("Debug: MainFrame--Error: Icon toolbar is already active, action cancelled"));
return -1;
}
CMFCPopupMenu::SetForceMenuFocus(FALSE);
//CMDIChildWndEx::m_bEnableFloatingBars = TRUE;
// Create ToolBar toolbar
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to Create Dialog ToolBar\n");
return -1;
}
m_wndMenuBar.EnableDocking(FALSE);
m_wndToolBar.EnableDocking(FALSE);
m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY);
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndMenuBar);
DockPane(&m_wndToolBar);
// DockPaneLeftOf(&m_wndToolBar);
CDockingManager::SetDockingMode(DT_SMART);
EnableAutoHidePanes(CBRS_ALIGN_ANY);
CRect rcClientOld;
CRect rcClientNew;
GetClientRect(rcClientOld);
RepositionBars(AFX_IDW_CONTROLBAR_FIRST, AFX_IDW_CONTROLBAR_LAST, 0, reposQuery, rcClientNew);
m_wndOutput.AddStringStatusTab(_T("I'm created 1 times"));
//m_wndToolBar.ResetAll();
RecalcLayout();
//m_wndToolBar.ShowPane(TRUE, FALSE, TRUE); // Show toolbar
return 0;
}
The images below:
Start from OnCreate with the panes properly "docked" mode
Destroyed ToolBar
ToolBar is switched from dock to float mode with Update 2 code. Ghost bars shown in the image. Trying to solve that issue.
Soooooo....anyone have any ideas on how I can solve this riddle?
Thanks!
Chris

Create multiple CDockablePanes onto an CDialog

I'm trying to do exactly the same as the article describes here:
"C++ MFC Feature Pack --> Create multiple CDockablePanes onto an CDialog"
I followed his procedure and now am able to undock and move the CDockablePane, but get the same crash when dock it back. In his own answer, he said he created the dummywnd by himself so MFC skipped the creation and the call to GetTopLevelFrame(). And this is where I got confused, how do I create the dummywnd exactly?
My second question is how do I exchange data between the CMyFrame and CDialog?
The person who asked and answered the question seems to be inactive for years and unreachable. Could anyone please help or have any ideas?
Thanks,
Edit:
I break the program and traced back exactly as the other author described. The dummy window mentioned above is actually in afxdragframeimpl.cpp:
void CMFCDragFrameImpl::MoveDragFrame(BOOL bForceMove)
where it creates:
m_pWndDummy = new CDummyDockablePane;
and calls:
m_pWndDummy->CreateEx(0, _T(""), AFXGetTopLevelFrame(m_pDraggedWnd), CRect(0, 0, 0, 0), FALSE, AFX_DUMMY_WND_ID, WS_CHILD);
And yes, I'm trying to create a CFrameWndEx as child window in my dialog, and then add child CDockablePane in that CFrameWndEx.
Basically I have a MFC dialogA with some controls, and within this dialogA I need some tear-off tabsXYZ, and I need to add some controls within each of the tear-off tabsXYZ. So this means each tear-off tabsXYZ is actually one child dialogB. So this comes to where I try to use CDockablePanes (CPaneDialog actually) within the dialogA.
BOOL CMyDlg::OnInitDialog()
{
CRect wndRect;
GetWindowRect(wndRect);
m_pFrame = new CMyFrame();
m_pFrame->Create(NULL, NULL, WS_CHILD | WS_VISIBLE | WS_BORDER, wndRect, this);
m_pFrame->MoveWindow(wndRect);
CDialog::OnInitDialog();
...
}
I don't recommend the above code where frame window is placed in a dialog, because CFrameWndEx does all sorts of strange things, it's easy to break this code. Surprisingly, it works fine on VS2015, I couldn't duplicate any crash. But the window's behavior is still odd.
It's better to make a new frame window, and place a child dialog in frame. For example:
class CMyFrame : public CFrameWndEx
{
CDialog m_dialog;
int OnCreate(LPCREATESTRUCT lpCreateStruct)
{
CFrameWndEx::OnCreate(lpCreateStruct);
m_dialog.Create(IDD_CHILD1, this);
CRect rc;
m_dialog.GetClientRect(&rc);
m_dialog.SetWindowPos(NULL, 0, 0, rc.right, rc.bottom, SWP_SHOWWINDOW);
return 1;
}
DECLARE_MESSAGE_MAP()
};
You open the window as follows:
void CMyMainFrame::OnButton()
{
CMyFrame *frame = new CMyFrame;
frame->LoadFrame(IDR_MAINFRAME,
WS_POPUPWINDOW | WS_THICKFRAME | WS_CAPTION | WS_SYSMENU, this);
frame->SetMenu(0);
frame->ShowWindow(SW_SHOW);
}
You can also create a child dialog and put that inside a docking pane. For example:
class CMyFrame : public CFrameWndEx
{
CDockablePane m_DockWnd;
CDialog m_dialog;
int OnCreate(LPCREATESTRUCT lpCreateStruct)
{
CFrameWndEx::OnCreate(lpCreateStruct);
CMFCVisualManager::SetDefaultManager(RUNTIME_CLASS(CMFCVisualManagerWindows));
CDockingManager::SetDockingMode(DT_SMART);
EnableAutoHidePanes(CBRS_ALIGN_ANY);
m_DockWnd.Create(_T("Test"), this, CRect(0, 0, 200, 200), TRUE, 0,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN |
CBRS_LEFT | CBRS_FLOAT_MULTI);
m_dialog.Create(IDD_PAGE1, &m_DockWnd);
CRect rdialog;
m_dialog.GetClientRect(&rdialog);
m_dialog.SetWindowPos(NULL, 0, 0, rdialog.Width(), rdialog.Height(), SWP_SHOWWINDOW);
m_DockWnd.SetMinSize(rdialog.Size());
m_DockWnd.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_DockWnd);
return 0;
}
...
};
Also remember, if your main window is also CFrameWndEx then you make something like the following calls in InitInstance:
SetRegistryKey(_T("MyCompany\\MyApp"));
SetRegistryBase(_T("MainFrame"));
When you open a new frame window you must change the registry base with
SetRegistryBase(_T("CMyFrame"));
Then change it back to SetRegistryBase(_T("MainFrame")) when you exit CMyFrame

Getting notifications about sizeHint changes from internal widgets

Small picture to depict what the problem is:
external_widget
+--------------------------------------------------+
| |
| |
| layout_widget |
| +-------------------------------+ |
| | | |
| | [internal_layout] | |
| | | |
| | | |
| | [Some Another Widget] | |
| +-------------------------------+ |
| |
+--------------------------------------------------+
layout_widget - just QWidget with vertical layout. It contains another internal_layout and another widgets.
internal_layout - layout where the widgets will be added and deleted in future.
external_widget - just QWidget with no layout, I control the position and size of layout widget and other widgets manually.
When I add some widgets in internal_layout - it sends LayoutRequest event (as far as I know, I saw this in Qt source codes). This event is catched by parent widget and parent widget tells his layout that something is changed which forces layout to recalculate layout_widget sizeHint() etc.
Do I understand this process right?
The problem is that sizeHint() is changed, but my external_widget doesn't know anything about that. I want to get notification about layout_widget sizeHint() changes. Is it possible?
I even tried to do this:
external widget ctor:
{
layout_widget->installEventFilter(this);
}
and tried to catch them:
void ...eventFilter(QObject* obj, QEvent* event )
{
if (obj == layout_widget && event == QEvent::LayoutRequest)
{
// TODO;
}
}
and I never got into "TODO" block.
Do layout_widget send some events or notifications that something was changed inside him and it should be resized, i.e. his sizeHint() has been changed?

mfc remove default toolbar

I've making simple desktop game in mfc for school project, I've managed to make my app be full screen and to remove menu bar but I can't find out how to remove default built in toolbar from my app or status bar. I tried everything that came across my mind...is there some kind of get function to call from your CWnd object to retrieve toolbar and status bar?
The creation of ToolBar and StatusBar is inside the CMainFrame class. You can easily remove them if you do not need them as follows:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
// *** creation of ToolBar starts, just remark/delete the whole block if you dont't want it
if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
// *** creation of ToolBar ends -------------------------------------------------------
// *** creation of StatusBar starts, just remark/delete the whole block if you dont't want it
if (!m_wndStatusBar.Create(this) ||
!m_wndStatusBar.SetIndicators(indicators,
sizeof(indicators)/sizeof(UINT)))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
// *** creation of StatusBar ends -------------------------------------------------------
// *** you have to remark/delete these lines too, if you removed the ToolBar above
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
// *** ToolBar extra ends -------------------------------------------------------
return 0;
}
m_pMainWnd->SetMenu(NULL); right before m_pMainWnd->ShowWindow(SW_SHOW); is called in the APPLICATION_NAME.cpp file.
Go to your resource file, double click on it , locate the toolbar, right click on it and choose delete :)

CSplitterWnd flip between horizontal and vertical splitter?

Suppose I have a splitter with 2 rows.
--------
| |
--------
| |
--------
How do I make it to this
---------
| | |
| | |
| | |
---------
switch from horizontal split to vertical split
without having to re-create the whole splitter?
Code is:
if (!m_wndSplitter.CreateStatic(this, 1, 2, WS_CHILD|WS_VISIBLE))
{
TRACE0("Failed to create splitter window\n");
return FALSE;
}
if (!m_wndSplitter.CreateView(0, 1, RUNTIME_CLASS(CWnd), CSize(200, 100), NULL))
{
TRACE0("Failed to create CView1\n");
return FALSE;
}
if (!m_wndSplitter.CreateView(0, 2, RUNTIME_CLASS(CWnd), CSize(500, 100), NULL))
{
TRACE0("Failed to create CView2\n");
return FALSE;
}
Don't use CreateStatic, just use Create on the splitter. Then you have a so called dynamic splitter, see more here.
When converting the splitter from horz to vert, you have to remove the views from the splitter and attach them again afterwards. You have to do this in your document-class. I can post a method to do this if needed.
Ok, here is a method to switch views in a pane:
CView* CGMBefundDoc::SwitchToView(CView* pNewView,int row,int col)
{
CMainFrame* pMainWnd = (CMainFrame*)AfxGetMainWnd();
CSplitterWnd* pSplitter = &pMainWnd->m_wndSplitter;
CView* pOldActiveView = reinterpret_cast<CView*>(pSplitter->GetPane(row,col));
ASSERT(pOldActiveView != pNewView);
// set flag so that document will not be deleted when view is destroyed
m_bAutoDelete = FALSE;
// Dettach existing view
RemoveView(pOldActiveView);
// set flag back to default
m_bAutoDelete = TRUE;
// Set the child window ID of the active view to the ID of the corresponding
// pane. Set the child ID of the previously active view to some other ID.
::SetWindowLong(pOldActiveView->m_hWnd, GWL_ID, 0);
::SetWindowLong(pNewView->m_hWnd,GWL_ID,pSplitter->IdFromRowCol(row,col));
// Show the newly active view and hide the inactive view.
pNewView->ShowWindow(SW_SHOW);
pOldActiveView->ShowWindow(SW_HIDE);
// Attach new view
AddView(pNewView);
// Set active
pSplitter->GetParentFrame()->SetActiveView(pNewView);
pSplitter->RecalcLayout();
return pOldActiveView;
}
I hope you get the idea, otherwise just ask.
-----------|----------|
| | |
| | |
| |----------|
| | |
| | |
-----------|----------|
2 column splitter with right side having 2 rows, one Up and one Down and another one with left side to the Up and Down ?