Professional UI Solutions
Site Map   /  Register
 
 

Forum

Please Log In to post a new message or reply to an existing one. If you are not registered, please register.

NOTE: Some forums may be read-only if you are not currently subscribed to our technical support services.

Forums » Prof-UIS Tech Support » how to create/destroy CExtControlBars at runtime??? Collapse All
Subject Author Date
Chris Thomas Sep 22, 2005 - 1:52 PM

--third attempt at posting--- sorry if there end up duplicates ---

I have an app with a modeless dialog that is created/destroyed via a toolbar button, like a toggle. I want to replace that with a docking bar that hosts the dialog, but I want to do it at runtime. You can move the floating bar around and close it, and it persists its location and size, so next time it shows where it was.

It is working but I’m having two problems:
1) can’t seem to reliably get the coordinates of the control bar. I think it has trouble compensating for the floating frame’s size. And it exhibits strange behavior on a second monitor - it insists on putting the floating bar at the same position, regardless of where you try to move it.
2) Something is wrong with the docking bar creation code. If you create it, it crashes if you try to dock it somewhere. I’m doing all the same initialization steps that the similar bars do in mainframe OnCreate().

I really don’t want to create placeholders in mainframe for the 7 or so dialogs I have. The dialogs aren’t created in mainframe, so if mainframe did create CExtControlBar placeholders, they would be hidden and empty - I don’t know if that is problematic or not.

I have two functions in mainframe - one for loading a CWnd into a CExtControlBar, and one for unloading. The loading function takes a CWnd* ptr and creates a new CExtControlBar, reparents the CWnd into it, and floats it. The unloader finds the bar and removes and deletes it.

What am I missing or doing wrong?

----------------

bool CMainFrame::LoadDockingWindow(const CString& csName, CWnd* pWnd /*, CPoint& pt*/)
{
    CExtControlBar* pBar = 0;
    if (m_mapControlBars.Lookup(csName, (void*&)pBar))    //bail if already exists, shouldn’t happen
        return false;

    //make a new CControlBar
    pBar = new CExtControlBar();
    if (!pBar->Create(csName,
                    this,
                    pWnd->GetDlgCtrlID(),
                    WS_CHILD|WS_VISIBLE
                    |CBRS_LEFT|CBRS_GRIPPER|CBRS_TOOLTIPS
                    |CBRS_FLYBY|CBRS_SIZE_DYNAMIC
                    |CBRS_HIDE_INPLACE))
        return false;

    CRect rc;
    pWnd->GetWindowRect(&rc);
    ScreenToClient(&rc);

TRACE("floating at (%d,%d) (%d x %d)\n", rc.left, rc.top, rc.Width(), rc.Height());
    pWnd->SetParent(pBar);
    pBar->EnableDocking( CBRS_ALIGN_ANY );
    pBar->SetInitDesiredPosFloating(rc.TopLeft());
    pBar->SetInitDesiredSizeFloating(rc.Size());
    FloatControlBar(pBar, CPoint(rc.left, rc.top));
    //??? doesn’t work -- pWnd->SetWindowPos(NULL, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER);        //activate the window
    pWnd->Invalidate();
    pWnd->UpdateWindow();
    m_mapControlBars.SetAt(csName, (void*)pBar);
    RecalcLayout();
    return true;
}

bool CMainFrame::UnloadDockingWindow(const CString& csName)
{
    CExtControlBar* pBar = 0;
    if (!m_mapControlBars.Lookup(csName, (void*&)pBar) || pBar == 0)     //bail if doesn’t exists, shouldn’t happen
        return false;
    m_mapControlBars.RemoveKey(csName);
    RemoveControlBar(pBar);
    pBar->DestroyWindow();
    delete pBar;
    RecalcLayout();
    return true;
}


Chris Thomas Sep 22, 2005 - 2:44 PM

I have more info -- first I solved the position problem by using the bar’s GetPosFloating() and GetSizeFloating() functions. However it still has funky behavior if you move the floating bar to the second monitor, destroy it, then create it. It won’t create at the position on the second monitor, rather it mysteriously puts it back on the first monitor, down in the right corner. Strange.

The docking on-the-fly is working better than I first reported. It docks and floats fine, except it ASSERTs when you dock the floating bar, then re-float it. It ASSERTs in CDockBar line 1186, in CExtDockBar::_RemovePlaceHolder():
    ASSERT( pBar != NULL ); // may be placeholder ID

Ignoring that ASSERT brings you to another ASSERT at the same place. Ignoring that one works, and voila the floating bar appears. So it could probably be a Debug-only problem, but my fellow programmers here would tar and feather me if they had to see those in debug mode...

So I must be doing something incorrect when I create the CExtControlBar...?

The other issue I’m having is a barrage of ASSERTs when the floating bar is up, and I right-click on unused control bar space to see the menu of control bars. I think this is because the command manager doesn’t know about the new floating bar’s id or name. Ignoring all those ASSERTs allows it to work, but you don’t see a menu item for the floating bar. How can I override that menu so it won’t allow the user to see or manipulate certain bars? Is there a magic flag buried somewhere to control each bar’s participation in this?

Thanks!




Technical Support Sep 23, 2005 - 10:05 AM

We appreciate your strong interest in Prof-UIS control bars but we would prefer to receive your project and debug it. The information in your message is not enough to suppose any source of the problem. We know the control bar positions are saved and restored correctly regardless of the monitor location. So, we really need something compilable and linkable.

Additionally we must make a very important note about your application design. You wrote that you have some modeless dialog which is converted into resizable control bar and vice versa on the fly. If fact, this UI solution is already available in Prof-UIS. It is called dynamic resizable control bar (the CExtDynamicControlBar class). This is an advanced version of the CExtControlBar resizable control bar class. The dynamic bars have the Window Options button in the non client area which allows you to make the bar always floating only absolutely like your modeless dialog. Please take a look at the MDI_DynamicBars and SDI_DynamicBars sample applications and try to play with their dynamic bars. We also recommend you read the article about dynamic control bars.


Chris Thomas Sep 26, 2005 - 3:18 PM

Ok I have a test app, I’ll email it to you. In the zip there is a readme.txt that details the issue, and I’ll include that readme.txt in the email body, just to make sure.

I’m hoping it is just somthing stupid that I am doing. Perhaps I am incorrectly assuming that a CExtControlBar instance with a child dialog always remain together as a pair, and the two live together regardless of floating, docked, or tabbed.

I understand your point about the application design. The problem I have is the app has a few modeless dialogs that appear at various times and stay for various lengths of time, created and maintained in parts of the app that are far away from CMainFrame::OnCreate(). I did look at the dynamic bars examples and I saw the Windows Options button. But does that do anything other than force floating instead of docking?

After reading the dynamic control bar article, I got the impression that these bars are still created in Mainframe::OnCreate(), and all of them have to exist at that point in time. Hey if you can get that test app to work with dynamic bars, I’d be happy with that.

We simply want to create a dialog, anywhere in the app, and tell mainframe to host it as a dockable entity. The user should be able to move and dock it anywhere, and terminate it by the X button or by some other UI that toggles it. That is all we want mainframe to do here.

Thanks!


Technical Support Sep 27, 2005 - 5:48 AM

We are still looking forward to your e-mail. Please ensure you sent it to support@prof-uis.com.

Chris Thomas Sep 27, 2005 - 8:00 AM

Sorry, I sent it to support@profuis.com, without the "-". FYI that is what your link on your home page says. I’ll resend it right away.

Technical Support Sep 27, 2005 - 11:56 AM

This message is both posted to the technical support forum and e-mailed to you. A modified version of your project is enclosed in the e-mail.

First of all, we added the following line to the constructor of the CMainFrame class:

CExtControlBar::g_bCloseOnlyOneBarInTabGroup = true;
This tells the resizable control bar to close only the one bar when the "X" button on the tab group is pressed. This is essential for your destroyable bars. Second, we recoded the CMainFrame::UnloadDockingWindow() window and it brings no problems now. The bForceNoOptimizeMode parameter of this method should be set to true when you invoke this method from CMainFrame::DestroyWindow(), i.e. when the frame enters its destruction sequence. So, the bar can be destroyed before saving states of other bars. We noticed that two dynamic control bars have the static entries in the message map of the main frame window. It seems these control bars are not fully dynamic or it’s done just for testing. We have also updated the source code for the CExtBarNcAreaButtonCloseIgnore::OnNcAreaClicked() method and added the message handler for the CExtControlBar::g_nMsgCreateTabbedBar registered windows message to the main frame window. This will make Prof-UIS bars using your CExtBarNcAreaButtonCloseIgnore class as the "X" button implementation in any resizable control bars. Finally, the implementation of your bars requires Visual Studio .NET-like implementation of handling commands for each resizable control bar instead of classic MFC’s show/hide control bar commands which are not compatible with the auto-hidable resizable control bars. You should simply add the following methods to the CMainFrame class:
void CMainFrame::OnUpdateControlBarMenu(CCmdUI* pCmdUI)
{
    CExtControlBar::DoFrameBarCheckUpdate(
        this,
        pCmdUI,
        false
        );
}
 
BOOL CMainFrame::OnBarCheck(UINT nID)
{
    return
        CExtControlBar::DoFrameBarCheckCmd(
        this,
        nID,
        false
        );
}



These methods will be used in the message map of the CMainFrame class instead of the methods with the same name defined in the CFrameWnd class.

As for replacing the bars in your project with the dynamic control bars, it is not very difficult and will have the same visual result. But if your SDI application uses the CExtTabPageContainerWnd window (or derived from it) as the main view window, all the dynamic bars will be able to switch their states to the page windows inside tab page container.

Chris Thomas Sep 27, 2005 - 12:59 PM

Thanks for such a quick response! Those fixes work great.