![]() |
||
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
Can I use views as children of control bars?From the start I will say that using CView-based classes to implement children of control bars is not the best idea. The MFC framework for doc/view/frame is not that flexible. There are a lot of issues related to this, and if you are not a MFC guru, it is likely you will run into trouble. There are cases when starting a new class from scratch is not desirable: if you already have a carefully crafted view class, or need functionality built in CView (like drag'n'drop, but with a little work you can add this functionality to a CWnd too), you can host views on the bars. See the Articles section for how to do this. Below are the reasons for which I gave you the warning: As an exercise, please look after CWnd::GetParentFrame() implementation in the MFC sources (wincore.cpp) and hunt for the places it is called from. A view has a close relationship with it's parent frame. The bad news is that the control bars can switch the parent frames: when a bar is docked, it is ultimately the child of CMainFrame (usually a CMDIFrameWnd for MDI or CFrameWnd for SDI). When it is floating, its parent frame is a CMiniDockFrameWnd, which in turn is child of the desktop (no parents). The things get more complicated when a document is involved - OnCloseDocument() destroys the parent frames of all its views. There are more like this, and I will not list them here. If you are curious, of if you are determined to put a view on a control bar, take a look at the articles in the Docking Windows section at CodeGuru, as well as at the ones in Advanced UI. You will find useful information if you also read the comments :) Here are the main issues: 1.doc template/doc/parent/view frame relationship
So, my advice is to use plain CWnd based controls where you can. Dialogs, toolbars(!), are good too. |
![]() |
![]() |
![]() |
When my bar is docked, the edges are not redrawn. Why?Check the styles you passed to Create(). The default value is WS_CHILD|WS_VISIBLE|CBRS_TOP. It is very likely you forgot the CBRS_TOP style (you can also use CBRS_BORDERS_3D - see CControlBar::PreCreateWindow() in MFC sources).
|
![]() |
![]() |
![]() |
How do I convince my left bar to go down as far as the status bar (preventing the bar at the bottom from taking over the whole frame width)?Replace the // EnableDocking(CBRS_ALIGN_ANY); // <-- comment this out EnableDocking(CBRS_ALIGN_TOP); EnableDocking(CBRS_ALIGN_LEFT); EnableDocking(CBRS_ALIGN_RIGHT); EnableDocking(CBRS_ALIGN_BOTTOM);This is not directly related with CSizingControlBar - you can use this trick even for toolbars. The explanation is that the frame layout is done by asking all immediate children with IDs in the range AFX_IDW_CONTROLBAR_FIRST .. AFX_IDW_CONTROLBAR_LAST about the size it will ocupy. The order is the one in which they are created, every bar subtracting its area from the remaining client area. The default sequence for an AppWizard generated application is status bar, top, bottom, left, and right dockbars. Just for fun: Move the Create() call for the status bar after the EnableDocking() call. Run your app and dock some bars at bottom and on sides - you will see the status bar in a strange location. OK, now revert the changes! :) |
![]() |
![]() |
![]() |
How to add a context menu to my bar?You can do this in many ways. I will show here the simplest method. First, you need a submenu in the main menu (the View submenu is great). Add there menu items of type ID_VIEW_MYBAR and add handlers in the mainframe (see both samples for this). Now handle WM_CONTEXTMENU in your bar: void CMyBar::OnContextMenu(CWnd* pWnd, CPoint point) { CMenu menu; menu.LoadMenu(IDR_MAINFRAME); menu.GetSubMenu(1)->TrackPopupMenu(TPM_LEFTALIGN, point.x, point.y, m_pDockSite); } The code above assumes you use the second submenu in IDR_MAINFRAME - this is the View menu for a default MDI AppWizard generated app. Rebuild and enjoy! |
![]() |
![]() |
![]() |
When I drag my floating bar over other bars, it tryies to dock, but I want it floating at that position. Is this a bug?No, it's the intended behavior. Just tell the user to press and hold down the Ctrl key while dragging the bar around - it will stay floating. |
![]() |
![]() |
![]() |
It is possible to disable floating so the bar will be always docked?Yes, but the tradeoff is that you will have to disable dragging completely, so the user will no longer be able to drag the bar from one side to another. For this, you will simply handle WM_LBUTTONDOWN and WM_LBUTTONDBLCLK in your class (like CMyBar) and do nothing in the handler implementations. This will prevent the bar to enter in the drag state. Resizing the bar in place (where it is docked) is still possible, also the hide button functionality is preserved, because they are triggered by NC mouse messages. |
![]() |
![]() |
![]() |
It is possible to disable docking so the bar will be always floating?This is simpler. In CMainFrame::OnCreate(), instead of this sequence: m_wndMyBar.EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndMyBar, AFX_IDW_DOCKBAR_LEFT); use this one: m_wndMyBar.EnableDocking(0); // no docking FloatControlBar(&m_wndMyBar, point); Where |
![]() |
![]() |
![]() |
How do I get a pointer to my bar/mainframe/view/etc.?1. Pointer to mainframe (CMainFrame)
CMainFrame* pMainFrame = (CMainFrame*) ::AfxGetMainWnd(); 1.2. From inside CMyBar: CMainFrame* pMainFrame = (CMainFrame*) m_pDockSite; 2. Pointer to a controlbar (CMyBar)
CControlBar* pBar = pMainFrame->GetControlBar(ID_MYBAR); CMyBar* pMyBar = (CMyBar*) pBar; 2.2. If you are in CMainFrame, you can use the member variable directly (like m_wndMyBar).
3. Pointer to a view
pMainFrame->GetDlgItem(AFX_IDW_PANE_FIRST); |
![]() |
![]() |
![]() |
How do I know if my bar is visible?First, get a pointer to the bar (see this topic), then: if (pMyBar->IsVisible()) ... |
![]() |
![]() |
![]() |
How do I show/hide my bar?Get pointers to the bar and to the main frame (see this topic), then: pMainFrame->ShowControlBar(pMyBar, TRUE); pMainFrame->ShowControlBar(pMyBar, FALSE); The code above shows/hides the bar immediatelly. If you want to show/hide multiple bars at once, you can pass TRUE for the optional bDelay parameter. The bars will be updated at the next idle time or specifically with a |
![]() |
![]() |
![]() |
How to disable the mainframe's accelerators when the bar (or a child of the bar) has the focus?Intercept PreTranslateMessage() somewhere in the pre-translation tree, then dispatch the keyboard messages. For example, this will work in many cases: BOOL CMyBar::PreTranslateMessage(MSG* pMsg) { if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) { // dipatch keyboard messages directly (skip main accelerators) ::TranslateMessage(pMsg); ::DispatchMessage(pMsg); return TRUE; } return baseCMyBar::PreTranslateMessage(pMsg); } |
![]() |
![]() |
![]() |
My child window is not redrawn properly when I resize the control bar. What should I do?This was a bug in previous versions (earlier than v2.41), caused by a wrong combination of window styles for the bar. You should update to the latest version.
m_wndChild.MoveWindow(rc); m_wndChild.Invalidate(); // <- Add this or, better, replace the MoveWindow() call with SetWindowPos(): m_wndChild.SetWindowPos(NULL, rc.left, rc.top, rc.Width(), rc.Height(), SWP_NOACTIVATE|SWP_NOZORDER|SWP_NOCOPYBITS); |
![]() |
![]() |
![]() |
I liked the raised borders from the previous versions.
|
![]() |
![]() |
![]() |
I want to do something when the bar is closing (the user clicks the "x" button).
|
![]() |
![]() |
![]() |
I want to make my changes directly in sizecbar.h/.cpp files.
|
![]() |
![]() |
![]() |
![]() |
![]() |