Pregunta

En mi MFC (Feature Pack) la aplicación se puede crear de forma dinámica paneles de conexión para mostrar gráficos / tablas etc.
Sin embargo, no quiero dejar que el usuario abra la misma cosa dos veces.

creo un panel de la siguiente manera:

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

Esto parece funcionar bien.

Así es como he tratado de comprobar si un panel ya existe. Un panel se identifica por su tipo (clase) y un parámetro.

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;
}

El problema con esto es que cuando cierro un panel, esto no es reconocido. El objeto CDockingManager sigue devolviendo el panel en los GetPanes () llamada.

¿Cómo puedo saber el gerente de no volver paneles que están cerradas?
o
¿Cómo puedo quitar el panel de una lista del panel, cuando está cerrado?


Actualizar

He buceado un poco más profundo y se encontró, que los objetos CWnd en realidad no son cerrados, al hacer clic en el botón 'x' en la barra de título, pero sólo sus contenedores.
Así que el verdadero problema parece ser la de cerrar realmente los paneles.
También ha cambiado la pregunta para reflejar mejor el problema.

¿Fue útil?

Solución

Como se describe en mi actualización, el problema para el gerente de soporte para darme paneles cerrado, fue que los cristales no eran en realidad cerradas. Sólo se cerraron sus envases; los propios paneles estaban ocultos.

Así que para realmente cerrar los paneles que hicieron caso omiso de los métodos siguientes en mi CMDIFrameWndEx derivan clase de marco principal:

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
}

Y el segundo:

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
}

Otros consejos

añadir a yor CMainFram una entrada msg como la siguiente:

ON_REGISTERED_MESSAGE(AFX_WM_ON_PRESS_CLOSE_BUTTON,OnClosePane)

OnClosePane tener este aspecto:

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 se llama en medio de CBasePane :: manejador OnLButtonDown, destruyendo ventana hará que su aserción de código, por lo que necesita para enviar mensajes (WM_CLOSE) en lugar de enviarlo, esto da CBasePane :: manejador OnLButtonDown la oportunidad de terminar la ejecución, mientras que el panel CVent siendo válida. y por la misma resone vuelvo verdadera evitar que los primeros, porque ya cerramos a través WM_CLOSE que destruirá la ventana también.

mensaje WM_RESETMEMBER se ha registrado mensaje de ventana para restablecer miembro de panel a null.

aplicación el siguiente aspecto:

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;
}

debe msg mapa de entradas como uno:

ON_REGISTERED_MESSAGE(WM_RESETMEMBER,OnResetMember)

y usted debe registrarse mensaje a nivel mundial como esto:

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

Me esperaba una llamada a CDockingManager :: RemovePaneFromDockManager cuando se está cerrando el panel para hacer el trabajo.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top