Frage

In meinem MFC (Feature Pack) Anwendung einer dynamisch können Andocken Scheiben Anzeige Charts / Tabellen erstellen usw.
Allerdings mag ich nicht zweimal der Benutzer öffnet die gleiche Sache lassen.

erstelle ich eine Scheibe wie folgt aus:

// Create CMyDockablePane pPane
pPane->Create(...);
pPane->EnableDocking(CBRS_ALIGN_ANY);
// Create CRect rcPane
pPane->FloatPane(rcPane);

Das scheint gut funktionieren.

Dies ist, wie ich versuche, zu überprüfen, ob eine Scheibe ist bereits vorhanden. Eine Scheibe wird identifiziert durch seinen Typ (Klasse) und Parameter.

BOOL CanOpenPane(const type_info & paneType, const CMyParameter & parameter) const
{
    CMainFrame* pFrm = GetMainFrame();
    CDockingManager* pDockMan = pFrm->GetDockingManager();


    // Check if there already is a pane of the same type which also has the same parameter.
    bool canOpen = true;
    CObList panes;
    pDockMan->GetPaneList(panes);
    POSITION pos = panes.GetHeadPosition();
    while (pos)
    {
        CMyDockablePane* pPane = dynamic_cast<CMyDockablePane*>(panes.GetNext(pos));
        if (NULL == pPane) { continue; }

        if (paneType == typeid(*pPane) &&
                pPane->GetParameter() == parameter)
        {
            canOpen = false;
            break;
        }
    }


    return canOpen;
}

Das Problem dabei ist, dass, wenn ich einen Bereich zu schließen, das nicht erkannt wird. Das CDockingManager Objekt noch kehrt die Scheibe in dem GetPanes () -Aufruf.

Wie kann ich den Manager sagen nicht Scheiben zurück, die geschlossen sind?
oder
Wie kann ich die Scheibe aus einer Scheibe Liste entfernen, wenn es geschlossen ist?


Update

tauchte ich ein wenig tiefer und fand, dass die CWnd-Objekte sind nicht wirklich geschlossen, wenn das Klicken auf ‚x‘ Button in der Titelleiste, sondern nur ihre Behälter.
So ist das eigentliche Problem scheint wirklich nahe den Scheiben zu sein.
Ich habe auch die Frage das Problem besser zu reflektieren.

War es hilfreich?

Lösung

Wie beschrieben in meinem Update, um das Problem für die Docking-Manager geben mir Scheiben geschlossen war, dass die Scheiben nicht tatsächlich geschlossen waren. Es wurden nur ihre Behälter geschlossen; die Scheiben selbst waren nur versteckt.

So wirklich nahe den Scheiben overrode ich die folgenden Methoden in meinem CMDIFrameWndEx Hauptrahmen-Klasse abgeleitet:

BOOL CMainFrame::OnCloseMiniFrame(CPaneFrameWnd* pWnd)
{
    if(0 == pWnd->GetPaneCount()) { return TRUE; } // No panes.. allow closing

    // Close all child panes of the miniframe that is about to be closed.
    //
    // Panes are placed inside a mini frame when they have the "floating" status.
    // Since I didn't find a way to iterate over the panes of a mini frame
    // (CMultiPaneFrameWnd can have several panes), we iterate over all panes
    // and close those whose parent frame is pWnd.

    CDockingManager* pDockMan = GetDockingManager();
    if(NULL != pDockMan)
    {
        CObList allPanes;
        pDockMan->GetPaneList(allPanes, TRUE, NULL, TRUE);

        for(POSITION pos = allPanes.GetHeadPosition(); pos != NULL;)
        {
            CDockablePane* pPane = dynamic_cast<CDockablePane*>(allPanes.GetNext(pos));
            if (NULL == pPane) { continue; }

            if(pWnd == pPane->GetParentMiniFrame())
            {
                pPane->PostMessage(WM_CLOSE); // Note: Post instead of Send
            }
        }

    }

    return TRUE; // Allow closing
}

Und die zweite:

BOOL CMainFrame::OnCloseDockingPane(CDockablePane* pWnd)
{
    CObList paneList;

    // We can get CDockablePanes and CTabbedPanes here.
    // The tabbed panes contain dockable panes.
    CTabbedPane* pTabbed = dynamic_cast<CTabbedPane*>(pWnd);
    CDockablePane* pDockable = dynamic_cast<CDockablePane*>(pWnd);
    if(NULL != pTabbed)
    {
        pTabbed->GetPaneList(paneList);
    }
    else if(NULL != pDockable)
    {
        paneList.InsertAfter(paneList.GetHeadPosition(), pDockable);
    }

    // Whatever it was, we now have a list of dockable panes, which we will close.
    for(POSITION pos = paneList.GetHeadPosition(); NULL != pos;)
    {
        CDockablePane* pPane = dynamic_cast<CDockablePane*>(paneList.GetNext(pos));
        ASSERT(NULL != pPane);


        // Let the window disappear and then recalculate the layout.
        // Not doing this causes problems with panes grouped together in a tabbed pane.
        pPane->ShowWindow(SW_HIDE);
        RecalcLayout();

        // Really close the window so the docking manager also doesn't know of it anymore.
        pPane->Reset();
        pPane->PostMessage(WM_CLOSE); // Note: Post instead of Send
    }


    return TRUE; // Allow closing
}

Andere Tipps

in dem yor CMainFram einen msg Eintrag wie folgt aus:

ON_REGISTERED_MESSAGE(AFX_WM_ON_PRESS_CLOSE_BUTTON,OnClosePane)

OnClosePane sieht wie folgt aus:

LRESULT CMainFrame::OnClosePane(WPARAM,LPARAM lp)
{
    CBasePane* pane = (CBasePane*)lp;
    int id = pane->GetDlgCtrlID();
    pane->ShowPane(FALSE, FALSE, FALSE);
    RemovePaneFromDockManager(pane,TRUE,TRUE,TRUE,NULL);
    AdjustDockingLayout();
    pane->PostMessage(WM_CLOSE);
    PostMessage(WM_RESETMEMBER,id,0);
    return (LRESULT)TRUE;//prevent close , we already close it
}

COUTION:

OnClosePane wird in der Mitte des CBasePane genannt :: OnLButtonDown Handler, Fenster zu zerstören wird Ihr Code assert machen, so dass Sie Post Nachricht benötigen (WM_CLOSE), anstatt sie zu senden, um dieses Gebens CBasePane :: OnLButtonDown Handler eine Chance, die Ausführung zu beenden, während die Scheibe noch gültig Hwnd. und für die gleiche resone i return true nahe zu verhindern, weil wir bereits in der Nähe es über WM_CLOSE, welches Fenster als auch zerstören.

WM_RESETMEMBER Nachricht ist registrierte Fenster Meldungsfenster Mitglied auf null zurückgesetzt werden.

es Implementierung sieht wie folgt aus:

LRESULT CMainFrame::OnResetMember(WPARAM wp,LPARAM)
{
    int id = (int)wp;
    switch(id)
    {
        case IDC_BIDBOND_TREE_PANE:
            m_pBBTreePane.reset((BBTreePane*)NULL);
            break;
        case IDC_REFTREE_PANE :
            m_pRefTreePane.reset((RefTreePane*)NULL);
            break;
        default :
            return (LRESULT)FALSE;//id warent found

    }
    return (LRESULT)TRUE;
}

Sie sollten MapEintrag wie ein Msg:

ON_REGISTERED_MESSAGE(WM_RESETMEMBER,OnResetMember)

und Sie sollten Nachricht registrieren global wie folgt aus:

const UINT WM_RESETMEMBER = ::RegisterWindowMessage(_T("WM_RESETMEMBER"));

würde ich einen Aufruf an CDockingManager :: RemovePaneFromDockManager wenn Sie Ihre Scheibe schließen die Arbeit zu tun.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top