Learn how easy it is to sync an existing GitHub or Google Code repo to a SourceForge project! See Demo

Close

Docking in the frame window

Anton123
2008-12-09
2013-05-28
  • Anton123
    Anton123
    2008-12-09

    Hi,

    I'm new into Win32++ - have been working with MFC years ago.

    Well, I want to play a little around in an old idea where I need an MDI app. with docking toolbars, tool windows etc., leaving a "small" area with MDI child views. It's like any other modern applications, like VS 2008 Express Ed. for instance.

    I notice that your Docking sample is using CFrame and CView. This seems not to be enough to fulfill my wishes, because you dock all other views to this CView. I want to dock to the frame instead (being able to close all child views without closing the docked windows).

    If I do understand the philosophy of CDockable, I would need to create a new CMDIFrame and a new CMDIChild inherited from CDockable instead of CWnd.

    But this work cannot be the right way to go. Can tou please help me getting the things right.

    Thanks
    Jens

     
    • David
      David
      2008-12-10

      Hi Jens,

      Thanks for your message.  Docking for MDI applications is a future direction for Win32++, but we can impliment docking with MDI applications with a bit of a hack.

      Firstly an overview of the docking philosophy in Win32++.  If you run the docking sample you will note the Simple docking view in the centre of the docking layout. This is the view window which remains when all possible windows are undocked. It is the view window for CMainFrame, and is referred to as the DockAncestor in the CDockable class. All other dockables dock to this window.

      In your case we need to make this dock ancestor a MDI client view. The easiest way to achieve this is to modify Win32++'s 'mdi.h'. Inside the declaration of CMDIFrame is a nested CMDIClient class. We need to modify the declaration of CMDIFrame to make CMDIClient public.

      You can than modify the existing Docking sample to support MDI with the following changes:

      1) Edit Win32++'s mdi.h (as described above)
      2) Start with a copy of the Docking sample and modify MainFrm.h as follows:
         - use #include "..\Win32++\mdi.h" instead of #include "Win32++\frame.h"
         - Inherit CMainFrame from CMDIFrame
         - Change m_DockView from CDockSimple to CDockMDI
      3) Add a CDockMDI class and CViewMDI class as follows:
         - add #include "..Win32++\mdi.h" to Views.h (before dockable.h)
         - Add CDockMDI to Dockables.h and CViewMDI to views.h as follow:

      class CDockMDI : public CDockable
      {
      public:
          CDockMDI() { SetView(m_View); }
          virtual ~CDockMDI() {}

      private:
          CViewMDI m_View;
      };
        
      class CViewMDI : public CMDIFrame::CMDIClient
      {
      public:
          CViewMDI() {}
          virtual ~CViewMDI() {}
      }; 
        
      Done...  We now have dockable windows wrapped around our MDI client window. We add MDI children in the usual way (it might make sense to add them maximised).

      Future versions of Win32++ will include a tabbed dockable view with a toolbar and a tabbed MDI view.

      Best regards,
      David

         

       
    • Anton123
      Anton123
      2008-12-11

      Hi David,

      Thanks for your answer. It was easy to get to work in a copy of your Docking sample. Initially I had some trouble to compile it in a new project, but now it compiles and runs fine in my own project.

      Is it just as easy to add a docking toolbar? Somehow it's the same question as what you just answered, because looking into Win32++ CToolbar is inherited from Cwnd, but it should be inherited from CDockable.

      Btw. I have followed your guidelines in the answer to Songmuh in july - "RE: How to set up Win32++ project from ground up". If I add this: "<comctl32.lib>", it won't compile. If I instead add "comctl32.lib", it does compile.

      Best regards,
      Jens

       
    • David
      David
      2008-12-11

      Hi Jens,

      Regarding a dockable toolbar ...
      This will not be as simple as adding MDI docking support. The CDockable object containing the toolbar will need to co-operate with the rebar control to add and remove rebar bands as appropriate. Either that or I'll do away with the rebar control entirly and come up with a home grown control that does something similar (MFC does this).

      To be honest, I've never been a big fan of toolbar undocking. This might sound like heresy, but in the past I've found it more of an annoyance rather than a desirable feature. Still it is a common feature in Microsoft applications and some people like it (or at least expect to see it), so I'll be adding this feature to Win32++ in due course. It will be the last docking feature I add to Win32++, after tabbed MDI and tabbed dockable containers with toolbars.

      Regarding "How to set up Win32++ project from ground up" ...
      Yes you are quite correct. The '< >' braces should not be used here. I must have been thinking of including a header file at the time.

      Best regards,
      David

       
      • Todor Totev
        Todor Totev
        2008-12-12

        David,
        thank you for all the improvements you make to Win32++, it forms as one of the solid UI framewoks which does not overwhelp the newbie gui programmer (that's me). If you are going to worrk on undockable toolbars, would you please consider implementing the Office / IE behaviour and allow toolbars to be locked in place?
        Kind regards,
        Todor

         
    • Anton123
      Anton123
      2008-12-12

      Hi David,

      I agree with you. If I think how often I use the docking toolbar feature in Microsoft products, the answer tends to be never. I guess it is a question of "being as good as MS"...

      Back to my questions...

      Today I have been fighting a lot to implement the MDI child window, but I can't bring it to work. I receive two exceptions: "CWnd::CreateEx ... Failed to Create Window" and "CMDIChild:CreateEx ... CreateEx failed".

      After adding "AddMDIChild(new CMDIChildText);" to the IDM_FILE_NEW event handler in
      CMainFrame::OnCommand, I add a copy of your CMDIChildSimple (from MDIdemo) and make the changes necessary to compile (basicly renaming CViewSimple to CViewSimple1).
      I started using my modified Docking sample, adding an event handler in CMainFrame::OnCommand, like this.

      Best regards,
      Jens

       
    • Anton123
      Anton123
      2008-12-12

      Sorry,

      of cause I'm adding "AddMDIChild(new CMDIChildSimple);" and NOT "AddMDIChild(new CMDIChildText);".

      Best regards,
      Jens

       
    • David
      David
      2008-12-13

      Yes, this is my mistake.  I should have tested my proposed changes further.

      To add a MDI child we will need to do the following:

      1) Modify Win32++'s mdi.h again.
      In CMDIFrame::CMDIClient::WndProc

      change
      CMDIFrame* pMDIFrame = (CMDIFrame*)FromHandle(m_hWndParent);
      to
      CMDIFrame* pMDIFrame = (CMDIFrame*)FromHandle(GetAncestor(m_hWnd));

      2)Override AddMDICHild in CMainFrame as follows:
      CMDIChild* CMainFrame::AddMDIChild(CMDIChild* pMDIChild)
      {
          m_MDIChildVect.push_back(pMDIChild);
          pMDIChild->Create(m_DockView.GetView()->GetHwnd());

          return pMDIChild;
      }

      I should stress that all this is a bit of a hack to push version 6.3 of Win32++ beyond what it was designed to support (namely Dockable MDI frames). I did note that the frame of a non-maximised MDI child wasn't always redrawn as expected for example. What you have here is an interim solution until docking for MDI frames is officially supported.

      Best regards,
      David

       
    • Anton123
      Anton123
      2008-12-13

      Hi David,

      I respect that you need time for the next release.

      But I have some comments.

      1. I suppose you mean that I add this line to Mainfrm.h

      CMDIChild* AddMDIChild(CMDIChild* pMDIChild);

      and the mentioned code into Mainfrm.cpp. At least it was what I did, and it works.

      2. If I undock a docked window, it is placed on top of the global Z-order. That is, if I bring another window into focus, it is still shown.

      3. When I create a MDI child, the docked window in focus keeps its focus.

      Best regards,
      Jens

       
    • Anton123
      Anton123
      2008-12-13

      Hi David,

      I respect that you need time for the next release.

      But I have some comments.

      1. I suppose you mean that I add this line to Mainfrm.h

      CMDIChild* AddMDIChild(CMDIChild* pMDIChild);

      and the mentioned code into Mainfrm.cpp. At least it was what I did, and it works.

      2. If I undock a docked window, it is placed on top of the global Z-order. That is, if I bring another window into focus, it is still shown.

      3. When I create a MDI child, the docked window in focus keeps its focus.

      Best regards,
      Jens

       
    • David
      David
      2008-12-14

      Hi Jens,

      Thanks for your follow-up message.

      Regarding point 1).
      Yes that's correct.

      Regarding point 2)
      I am aware of a Z order problem for undocked windows. If you're reporting the same problem I'm thinking of, that issue should already be fixed in the code for next version under development. You can download a copy of that code using SVN. Needless to say, at any time the development code may contain bugs or incomplete features, so always treat it as beta code. At the moment, however, it contains no known issues.

      Regarding point 3)
      That one doesn't surprise me, but its a handy reminder to check for that behaviour when docking in MDI frames is officially supported. Sending a WM_MOUSEACTIVATE message to the MDI client window seems to do the trick.  Try changing CMainFrame::AddMDIChild as follows:
      CMDIChild* CMainFrame::AddMDIChild(CMDIChild* pMDIChild)
      {
          m_MDIChildVect.push_back(pMDIChild);
          m_DockView.GetView()->SendMessage(WM_MOUSEACTIVATE, (WPARAM)m_hWnd, (LPARAM)MA_ACTIVATE);
          pMDIChild->Create(m_DockView.GetView()->GetHwnd());

          return pMDIChild;
      }

      Best regards,
      David