I' m new with MFC. I needed to create a floating toolbar (CToolBar) with no option of docking and save and restore its last pos.
The toolbar also should be active all the time, but its NOT.
When I'm openning a new child window (dialog for instance) from the mainframe, the floating tool bar become not active (I can not click on its buttons, or drag it etc..).
In the past I've used CDiaolog with Overlapped style and it was floating and always active as I needed. Is it possible to do the same with my Floating Toolbar? Thanks
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
toolbarIconSize.cx = toolbarIconSize.cy = TOOLBAR_MAIN_ICON_SIZE;
if ( !m_wndMyFloatingToolbar.Create(this,m_wndMyFloatingToolbar.GetBarStyle() |WS_EX_PALETTEWINDOW | WS_EX_TOPMOST |CBRS_FLOATING | WS_VISIBLE) ||
!m_wndMyFloatingToolbar.LoadToolBar(IDR_GENERAL_TOOLBAR, toolbarIconSize))
{
TRACE0("Failed to create My Floating Toolbar\n");
return -1; // fail to create
}
m_wndMyFloatingToolbar.EnableDocking(0);
EnableDocking(0);
if (!CreateCtrlBar())
{
TRACE0("Failed to create ctrl toolbar\n");
return -1; // fail to create
}
// ...
//...
return 0;
}
void CMainFrame::OnViewToolBar()
{
// ...
//...
CPoint Pos = MyFloatingToolbarGetLastPosition(); \\Get last pos
FloatControlBar( &m_wndMyFloatingToolbar, Pos, CBRS_ALIGN_LEFT );
MyFloatingToolbarSetIsVisible();
FloatControlBar( &m_wndMyFloatingToolbar, Pos, CBRS_ALIGN_LEFT );
}
void CMainFrame::MyFloatingToolbarSetIsVisible()
{
WINDOWPLACEMENT wp;
m_wndMyFloatingToolbar.GetParent()->GetParent()->GetWindowPlacement(&wp);
wp.showCmd = SW_SHOW;
m_wndMyFloatingToolbar.GetParent()->GetParent()->SetWindowPlacement(&wp);
m_wndMyFloatingToolbar.GetParent()->GetWindowPlacement(&wp);
wp.showCmd = SW_SHOW;
m_wndMyFloatingToolbar.GetParent()->SetWindowPlacement(&wp);
m_wndMyFloatingToolbar.GetWindowPlacement(&wp);
wp.showCmd = SW_SHOW;
m_wndMyFloatingToolbar.SetWindowPlacement(&wp);
}
void CWJToolBar::OnWindowPosChanging(WINDOWPOS FAR* lpwndpos)
{
CToolBar::OnWindowPosChanging(lpwndpos);
if ( GetBarStyle() & CBRS_FLOATING )
{
if((lpwndpos->flags & SWP_HIDEWINDOW) && ((this->GetParentFrame())->m_hWnd !=(this->GetTopLevelFrame())->m_hWnd))
{
CMainFrame* mf = (CMainFrame*)(AfxGetApp()->GetMainWnd());
mf->MyFloatingToolbarSavePosition();
}
}
}
You may need to debug to view its coordinates if they are correctly set. Be independent. :p
Based on your current posted code, I don't see the point of your stored data, try this
hiding your toolbar
saving its position data
changing your parent windows position and
reloading your saved coordinates.
The saved data becomes incorrect values then.
I suggest you capture the position to which you want to add your toolbar live . This makes your toolbar application more generic.
So,
Save your toolbar's i.e top-left distance to its parent windows, not its coordinates
Get your parent windows coordinates
Reload your toolbar based on the saved distance
There are of course other ways to do this but I think this is more trivial to accomplish what you may be looking for.
Use CMFCToolBar (instead CToolBar), then you need only 2 commands, to achieve this.
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWndEx::OnCreate(lpCreateStruct) == -1)
return -1;
:
m_wndToolBar.SetPermament(TRUE); // it removes CloseButton (=always active)
CRect rect;
GetClientRect(&rect);
ClientToScreen(rect);
rect.OffsetRect(100, 20);
m_wndToolBar.FloatPane(rect); // Float and move it to your wished coordinates
:
}
Related
I want my Dialog to communicate with my existing view outside of an OK response (so using an apply or similar). I assume Messages are the best way to do this.
I'm sure there are not a lot of MFC questions these days, so I hope someone is able to help.
Creating a new project via the wizard, I add a dialog (let's say a CPropertySheet) that is spawned by the view.
MyPropertiesSheet ps(_T("MyPropertiesSheet"));
if (ps.DoModal() == IDOK) {
// I don't care about this section
}
At first, I assumed that when I click 'apply' I would be able to send a message to the view and have it do something (as it was spawned in the view); however, I cannot pass messages directly to the view.
From the Dialog I use:
GetParent()->SendMessage(WM_BUTTON1, 0, 0);
I can catch the message within my MainFrm (a CmainFrame) which will launch the specified Button1() function, but I cannot catch the message in the view using the same code (below).
BEGIN_MESSAGE_MAP(CMainFrame, CMDIFrameWndEx)
...
ON_MESSAGE(WM_BUTTON1, Button1)
END_MESSAGE_MAP()
It makes sense as I guess the View is a child of the MainFrm and the Dialog belongs to the MainFrm, not the View.
My Programming Windows with MFC (2nd ed), by Jeff Prosise, uses a custom OnCreate to get a reference to the View by creating it manually, but I really don't want to have to do this as it seems rather complex. I am sure I will end up creating a lot of problems that way. The default OnCreate seems to have no obvious reference to my view (included for example, but feel free to skip this).
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIFrameWndEx::OnCreate(lpCreateStruct) == -1)
return -1;
BOOL bNameValid;
CMDITabInfo mdiTabParams;
mdiTabParams.m_style = CMFCTabCtrl::STYLE_3D_ONENOTE; // other styles available...
mdiTabParams.m_bActiveTabCloseButton = TRUE; // set to FALSE to place close button at right of tab area
mdiTabParams.m_bTabIcons = FALSE; // set to TRUE to enable document icons on MDI taba
mdiTabParams.m_bAutoColor = TRUE; // set to FALSE to disable auto-coloring of MDI tabs
mdiTabParams.m_bDocumentMenu = TRUE; // enable the document menu at the right edge of the tab area
EnableMDITabbedGroups(TRUE, mdiTabParams);
if (!m_wndMenuBar.Create(this))
{
TRACE0("Failed to create menubar\n");
return -1; // fail to create
}
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);
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(theApp.m_bHiColorIcons ? IDR_MAINFRAME_256 : IDR_MAINFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
CString strToolBarName;
bNameValid = strToolBarName.LoadString(IDS_TOOLBAR_STANDARD);
ASSERT(bNameValid);
m_wndToolBar.SetWindowText(strToolBarName);
CString strCustomize;
bNameValid = strCustomize.LoadString(IDS_TOOLBAR_CUSTOMIZE);
ASSERT(bNameValid);
m_wndToolBar.EnableCustomizeButton(TRUE, ID_VIEW_CUSTOMIZE, strCustomize);
// Allow user-defined toolbars operations:
InitUserToolbars(nullptr, uiFirstUserToolBarId, uiLastUserToolBarId);
if (!m_wndStatusBar.Create(this))
{
TRACE0("Failed to create status bar\n");
return -1; // fail to create
}
m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT));
// TODO: Delete these five lines if you don't want the toolbar and menubar to be dockable
m_wndMenuBar.EnableDocking(CBRS_ALIGN_ANY);
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
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);
// Load menu item image (not placed on any standard toolbars):
CMFCToolBar::AddToolBarForImageCollection(IDR_MENU_IMAGES, theApp.m_bHiColorIcons ? IDB_MENU_IMAGES_24 : 0);
// create docking windows
if (!CreateDockingWindows())
{
TRACE0("Failed to create docking windows\n");
return -1;
}
m_wndFileView.EnableDocking(CBRS_ALIGN_ANY);
m_wndClassView.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndFileView);
CDockablePane* pTabbedBar = nullptr;
m_wndClassView.AttachToTabWnd(&m_wndFileView, DM_SHOW, TRUE, &pTabbedBar);
m_wndOutput.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndOutput);
m_wndProperties.EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndProperties);
// set the visual manager and style based on persisted value
OnApplicationLook(theApp.m_nAppLook);
// Enable enhanced windows management dialog
EnableWindowsDialog(ID_WINDOW_MANAGER, ID_WINDOW_MANAGER, TRUE);
// Enable toolbar and docking window menu replacement
EnablePaneMenu(TRUE, ID_VIEW_CUSTOMIZE, strCustomize, ID_VIEW_TOOLBAR);
// enable quick (Alt+drag) toolbar customization
CMFCToolBar::EnableQuickCustomization();
if (CMFCToolBar::GetUserImages() == nullptr)
{
// load user-defined toolbar images
if (m_UserImages.Load(_T(".\\UserImages.bmp")))
{
CMFCToolBar::SetUserImages(&m_UserImages);
}
}
// enable menu personalization (most-recently used commands)
// TODO: define your own basic commands, ensuring that each pulldown menu has at least one basic command.
CList<UINT, UINT> lstBasicCommands;
lstBasicCommands.AddTail(ID_FILE_NEW);
lstBasicCommands.AddTail(ID_FILE_OPEN);
lstBasicCommands.AddTail(ID_FILE_SAVE);
lstBasicCommands.AddTail(ID_FILE_PRINT);
lstBasicCommands.AddTail(ID_APP_EXIT);
lstBasicCommands.AddTail(ID_EDIT_CUT);
lstBasicCommands.AddTail(ID_EDIT_PASTE);
lstBasicCommands.AddTail(ID_EDIT_UNDO);
lstBasicCommands.AddTail(ID_APP_ABOUT);
lstBasicCommands.AddTail(ID_VIEW_STATUS_BAR);
lstBasicCommands.AddTail(ID_VIEW_TOOLBAR);
lstBasicCommands.AddTail(ID_VIEW_APPLOOK_OFF_2003);
lstBasicCommands.AddTail(ID_VIEW_APPLOOK_VS_2005);
lstBasicCommands.AddTail(ID_VIEW_APPLOOK_OFF_2007_BLUE);
lstBasicCommands.AddTail(ID_VIEW_APPLOOK_OFF_2007_SILVER);
lstBasicCommands.AddTail(ID_VIEW_APPLOOK_OFF_2007_BLACK);
lstBasicCommands.AddTail(ID_VIEW_APPLOOK_OFF_2007_AQUA);
lstBasicCommands.AddTail(ID_VIEW_APPLOOK_WINDOWS_7);
lstBasicCommands.AddTail(ID_SORTING_SORTALPHABETIC);
lstBasicCommands.AddTail(ID_SORTING_SORTBYTYPE);
lstBasicCommands.AddTail(ID_SORTING_SORTBYACCESS);
lstBasicCommands.AddTail(ID_SORTING_GROUPBYTYPE);
CMFCToolBar::SetBasicCommands(lstBasicCommands);
// Switch the order of document name and application name on the window title bar. This
// improves the usability of the taskbar because the document name is visible with the thumbnail.
ModifyStyle(0, FWS_PREFIXTITLE);
return 0;
}
I assume there must be a way to get a handle to my View from MainFrm.
I've tried:
auto pView = GetActiveView();
if (pView == NULL) {
std::string error = "Unable to get Active View\n";
TRACE(error.c_str());
}
else {
pView->SendMessage(WM_BUTTON1, 0, 0);
}
but this is returning NULL (so I can't use that to send a message).
I'm not even sure I need this, but I am interested in why this is not working and why I can't get a handle to my View from the MainFrm.
For a simple solution, I would post your command WM_BUTTON1 with WM_COMMAND. Then the command is routed the MFC way MSDN (
MDI: Main frame, active child frame, active view, active document, application).
No need to handle and forward it in CMainframe. It does automatically for you.
In your CDialog:
AfxGetMainWnd()->PostMessage(WM_COMMAND, WM_BUTTON1, 0);
Add your handler in your CView
ON_COMMAND(WM_BUTTON1, &CMyView::OnButton)
No guarantees...from memory mostly. I haven't used CMDIFrameWndEx, only CMDIFrameWnd, but I assume it should work for the derived Ex variant...seemed like that was your main frame class.
// pseudo code
CMDIFrameWndEx* pFrame = DYNAMIC_DOWNCAST(CMDIFrameWndEx, AfxGetMainWnd()); // doesn't always work for OLE servers
if (pFrame)
{
CMDIChileWnd* pMDIChild = pFrame->MDIGetActive();
if (pMDIChild)
{
CYourView* pYourView = DYNAMIC_DOWNCAST(CYourView, pMDIChild->GetActiveView());
if (pYourView)
{
// do something
}
}
}
The miniframe class CPaneFrameWnd contains bug in smart docking algorithm!
This class used in MFC as miniframe for floating panes and can dock its to parent frame dock sites or to tabbed panes. It works fine when all panes can be docked to main frame only, but when panes docked to the child frame in MDI applications this class have a bug. Steps to reproduce the bug:
Undock some pane to float state.
Save docking state in MDI child frame: GetDockingManager()->SaveState(...)
Restore docking state for this MDI child frame: GetDockingManager()->LoadState(...); GetDockingManager()->SetDockState();
And try to dock this pane to same frame side by the mouse.
You can't this. The pane are moved by mouse to frame side but NOT DOCKED.
Bug in CPaneFrameWnd class source. In many places class uses code m_pDockManager != NULL ? m_pDockManager : afxGlobalUtils.GetDockingManager(GetParent()); for access its dockmanager.
But in some places of class this code looks like m_pDockManager != NULL ? m_pDockManager : afxGlobalUtils.GetDockingManager(this);. And this is reason of the bug - global function afxGlobalUtils.GetDockingManager() can't get dock manager from this pointer and try to get it from parent window of this pointer. It looks like pManager != NULL ? pManager : GetDockingManager(pWnd->GetParent());. But class CPaneFrameWnd have INLINE NONVIRTUAL GetParent() method that can't be accessed by afxGlobalUtils.GetDockingManager(). So, after some recursions afxGlobalUtils.GetDockingManager() returns dockmanager for MAIN app frame! And of course this dockmanager is not same as docmanager for MDI child frame.
Single right solution is to change all m_pDockManager != NULL ? m_pDockManager : afxGlobalUtils.GetDockingManager(this); to m_pDockManager != NULL ? m_pDockManager : afxGlobalUtils.GetDockingManager(GetParent()); in CPaneFrameWnd source (afxpaneframewnd.cpp file).
But this is requires patch to MFC code. And all of us knows how Microsoft lazy.
May be somebody knows how to fix this bug in current MFC release ?
I found the workaround for bug fixing. As mentioned in question, main problem that the mini-frame class CPaneFrameWnd have the m_pDockManager property which is not initialized (it have nullptr value). So, in some situations class CPaneFrameWnd can't find the right dockmanager from parent. Workaround for the bug is force initialize all mini-frames m_pDockManager property. Good place for this is the restoring docking state from registry (step 3 in question).
The sample for right save and load child frame docking state:
// Save docking state for CChildFrame class (inherited from CMDIChildWndEx)
void CChildFrame::SaveBarState(LPCTSTR lpszProfileName) const
{
const_cast<CChildFrame*>(this)->GetDockingManager()->SaveState(lpszProfileName);
CObList list;
const_cast<CChildFrame*>(this)->GetDockingManager()->GetPaneList(list, FALSE, NULL, FALSE);
if (list.GetCount() > 0) {
POSITION pos = list.GetTailPosition();
while (pos != NULL) {
CMFCToolBar* pToolBar = DYNAMIC_DOWNCAST(CMFCToolBar, list.GetPrev(pos));
if (pToolBar != nullptr) {
pToolBar->SaveState(lpszProfileName);
}
}
}
}
// Restore docking state for CChildFrame class (inherited from CMDIChildWndEx)
void CChildFrame::LoadBarState(LPCTSTR lpszProfileName)
{
CObList list;
GetDockingManager()->GetPaneList(list, FALSE, NULL, FALSE);
if (list.GetCount() > 0) {
POSITION pos = list.GetTailPosition();
while (pos != NULL) {
CMFCToolBar* pToolBar = DYNAMIC_DOWNCAST(CMFCToolBar, list.GetPrev(pos));
if (pToolBar != nullptr) {
pToolBar->LoadState(lpszProfileName);
}
}
}
GetDockingManager()->LoadState(lpszProfileName);
GetDockingManager()->SetDockState();
GetDockingManager()->ShowDelayShowMiniFrames(TRUE);
// MFC BUGFIX: force assigning the child frame docking manager to all miniframes.
for (POSITION pos = GetDockingManager()->GetMiniFrames().GetHeadPosition(); pos != NULL;)
{
CWnd* pWndNext = (CWnd*)GetDockingManager()->GetMiniFrames().GetNext(pos);
if (pWndNext != nullptr && pWndNext->IsKindOf(RUNTIME_CLASS(CPaneFrameWnd))) {
STATIC_DOWNCAST(CPaneFrameWnd, pWndNext)->SetDockingManager(GetDockingManager());
}
}
}
How-to use this code:
// creating child frame and its panes, loading the saved panes docking state.
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
bool bRes = TBase::OnCreate(lpCreateStruct) == 0;
if (bRes)
{
// enable docking
EnableDocking(CBRS_ALIGN_ANY);
// enable Visual Studio 2005 style docking window behavior
CDockingManager::SetDockingMode(DT_SMART);
// Creating toolbar, statusbar and panes. Dock them to default places.
{
// ....
}
}
if (bRes) {
LoadBarState(theApp.GetRegSectionPath(_T("ChildFrame")));
}
return bRes ? 0 : 1;
}
// destroy child frame and save panes docking state.
void CChildFrame::OnDestroy()
{
SaveBarState(theApp.GetRegSectionPath(_T("ChildFrame")));
TBase::OnDestroy();
}
Full sample source code.
I have a resizable dialog that contains a CTabCtrl, the tab control has 4 tabs that when clicked on displays one of four different CTreeCtrls.
I have derived a class from CTabCtrl, which keeps track of its "child" controls like so:
...
class Container: public CTabCtrl {
vector<CWnd*> _children;
....
int Container::AddTab(CWnd* Child) {
CString txt;Child->GetWindowText(txt);
_children.push_back(Child);
int idx = this->InsertItem(this->GetItemCount(), txt, 0);
if(idx == 0) {
CRect c;
this->GetWindowRect(&c);
GetParent()->ScreenToClient(&c);
this->AdjustRect(FALSE, c);
Child->SetWindowPos(&wndTop, c.left, c.top, c.Width(), c.Height(), SWP_SHOWWINDOW);
this->SetCurSel(idx);
} else Child->ShowWindow(SW_HIDE);
return idx;
}
And I attempt to draw the child controls like so:
void Container::OnTabChanging(NMHDR*, LRESULT* pResult) { // hide the changed from tab
int selected = this->GetCurSel();
if(selected != -1)
{
// move old window to bottom of the zorder and hide
_children[selected]->SetWindowPos(&wndBottom, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOMOVE|SWP_HIDEWINDOW);
ASSERT(!_children[selected]->IsWindowVisible());
}
*pResult = 0;
}
// show the child for the tab being changed to
void CNodeContainer::OnTabChanged(NMHDR* pNMHDR, LRESULT* pResult) {
int selected = this->GetCurSel();
ASSERT(selected!=-1);
CRect c;
this->GetWindowRect(&c);
GetParent()->ScreenToClient(&c);
this->AdjustRect(FALSE, c);
_children[selected]->SetWindowPos(&wndTop, c.left, c.top, c.Width(), c.Height(), SWP_SHOWWINDOW|SWP_FRAMECHANGED);
*pResult = 0;
}
However the child controls, whilst they appear, don't always draw correctly, they sort of mix up their content together and only show the right content when i click on them (the actual tree controls).
Is this the best way of drawing and moving windows around in the zorder, what am I missing?
Many thanks
bg
Instead of just changing the z-order of your children, completely hide every child except the top one. I use the same approach in a custom CTabCtrl and it works fine.
Its fixed now - the problem came from the fact that the in the resize code for the tabctrl, I was using movewindow to move the child windows into place - This was changing the zorder of the child windows.
This could solve the problem after your window or tab apears. Try to use
this->RedrawWindow();
In OnTabChanging() function before it returns.
This question is a follow up of my previous question.
First thanks for the links and examples, they do work voor a CMDIChildWnd derived CChildFrame class, but not for a CMDIChildWndEx derived one.
What i want to do:
I want to create a toolbar in the CChildFrame window (derived from CMDIChildWndEx !!)
What i have done so far:
1) Created a MDI Tabbed documents CView project using VS2008Pro App-wizard.
2) In CChildFrame i added OnCreate()
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIChildWndEx::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
if (!m_wndToolBar.Create(this) ||
!m_wndToolBar.LoadToolBar(IDR_CHILDFRAME))
{
TRACE0("Failed to create toolbar\n");
return -1; // fail to create
}
// TODO: Remove this if you don't want tool tips or a
// resizeable toolbar
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() |
CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC);
// TODO: Delete these three lines if you don't want the toolbar
// to be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar); // Goes wrong here !!
return 0;
}
it compiles and runs and halts into an ASSERT in winfrm2.cpp (line
92) :
void CFrameWnd::DockControlBar(CControlBar* pBar, CDockBar* pDockBar,
LPCRECT lpRect)
{
ENSURE_ARG(pBar != NULL);
// make sure CControlBar::EnableDocking has been called
ASSERT(pBar->m_pDockContext != NULL);
if (pDockBar == NULL)
{
for (int i = 0; i < 4; i++)
{
if ((dwDockBarMap[i][1] & CBRS_ALIGN_ANY) ==
(pBar->m_dwStyle & CBRS_ALIGN_ANY))
{
pDockBar = (CDockBar*)GetControlBar(dwDockBarMap[i][0]);
/* --------> goes wrong here ------> */ ASSERT(pDockBar != NULL);
// assert fails when initial CBRS_ of bar does not
// match available docking sites, as set by EnableDocking()
break;
}
}
}
ENSURE_ARG(pDockBar != NULL);
ASSERT(m_listControlBars.Find(pBar) != NULL);
ASSERT(pBar->m_pDockSite == this);
// if this assertion occurred it is because the parent of pBar was
not initially
// this CFrameWnd when pBar's OnCreate was called
// i.e. this control bar should have been created with a different
parent initially
pDockBar->DockControlBar(pBar, lpRect);
}
in line 92 :
ASSERT(pDockBar != NULL);
// assert fails when initial CBRS_ of bar does not
// match available docking sites, as set by EnableDocking()
the source here even gives some explanation of what goes wrong here
but i dont know how to match 'initial CBRS_ of bar with those set by
EnableDocking()''
Does this even work for a CMDIChildWndEx derived CChildFrame class ?
Well so my question is does any one know how to add a toolbar to a
CMDIChildWndEx derived CChildFrame class ?
Any suggestions on how to get this working ?
My project is here :
http://www.4shared.com/file/235762968/49b8b97a/GUI50.html
Any help would be greatly appreciated !
This seems to work for a CMFCToolBar
int CChildFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CMDIChildWndEx::OnCreate(lpCreateStruct) == -1)
return -1;
m_wndToolBar.Create(this, AFX_DEFAULT_TOOLBAR_STYLE, IDR_CHILDFRAME);
m_wndToolBar.LoadToolBar(IDR_CHILDFRAME, 0, 0, TRUE );
m_wndToolBar.SetPaneStyle( CBRS_TOOLTIPS | CBRS_FLYBY| CBRS_BOTTOM);
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockPane(&m_wndToolBar);
return 0;
}
You should set m_bEnableFloatingBars = TRUE in MDIChild constructor. Without this your toolbar will no be docked by mouse, only static docking.
So I'm in a situation where I need to know when a top level window gets created. I'm working at the Xlib/Xt level and on a Window Manager that doesn't support the EWMH specification. My idea is to hook into the root window's SubstructureNotify events. But things are not as simple as just that.
The problem is that not every CreateNotify event corresponds to the creation of a [b]top level[/b] window. So what I think I need to do is test the window I get from the event somehow to confirm that it is a top level window. I've got close, but some spurious windows still make it through my net. For example, in a GTK application if you have a dropdown box and you click it, a new window is created that I can't figure out how to catch and ignore. Such a window is troublesomely indistinguishable from a typical top level application window.
Here's what I have so far:
// I am omiting (tons of) cleanup code and where I set the display and toplevel variables.
Display* display;
Widget toplevel;
bool has_name(Window window)
{
XTextProperty data = XTextProperty ();
return (!XGetWMName (display, window, &data));
}
bool has_client_leader(Window window)
{
unsigned long nitems = 0;
unsigned char* data = 0;
Atom actual_type;
int actual_format;
unsigned long bytes;
// WM_CLIENT_LEADER is an interned Atom for the WM_CLIENT_LEADER property
int status = XGetWindowProperty (display, window, WM_CLIENT_LEADER, 0L, (~0L), False,
AnyPropertyType, &actual_type, &actual_format, &nitems, &bytes, &data);
if (status != Success || acutal_type == None) return false;
Window* leader = reinterpret_cast<Window*> (data);
return (*leader != 0);
}
bool has_class(Window window)
{
XClassHint data = XClassHint ();
return (!GetClassHint (display, window, &data));
}
void handle_event(Widget widget, XtPointer, XEvent* event, Boolean*)
{
if (event->type != CreateNotify) return;
Window w = event->xcreatewindow.window;
// confirm window has a name
if (!has_name (w)) return;
// confirm window is a client window
Window client = XmuClientWindow (display, w);
if (!client || client != w) return;
// confirm window has a client leader that is not 0x0
if (!has_client_leader (client)) return;
// confirm window has a class
if (!has_class (client)) return;
// The window has passed all our checks!
// Go on to do stuff with the window ...
}
int main(int argc, char* argv[])
{
// ...
// Setting up the event handler for SubstructureNotify on root window
Window root_window = XDefaultRootWindow (display);
Widget dummy = XtCreateWidget ("dummy", coreWidgetClass, toplevel, 0, 0);
XtRegisterDrawable (display, root_window, dummy);
XSelectInput (display, root_window, SubstructureNotifyMask);
XtAddRawEventHandler (dummy, SubstructureNotifyMask, False, handle_event, 0);
// ...
}
A long shot, but does anyone have any ideas I could try? I can't think of much else I can really do here.
I assume you're familiar with the ICCCM and its long-winded discussion.
Have you checked the WM_TRANSIENT_FOR property?