문제

내 MFC (피처 팩) 응용 프로그램에서는 차트/테이블 등을 표시하기 위해 도킹 접점을 동적으로 생성 할 수 있습니다.
그러나 사용자가 같은 것을 두 번 열어두고 싶지 않습니다.

나는 다음과 같은 창을 만듭니다.

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

이것은 잘 작동하는 것 같습니다.

이것이 바로 창이 이미 존재하는지 확인하려고 시도한 방법입니다. 창은 유형 (클래스) 및 매개 변수로 식별됩니다.

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

이것의 문제는 창을 닫을 때 이것이 인식되지 않는다는 것입니다. CdockingManager 객체는 여전히 getPanes () 호출에서 창을 반환합니다.

관리자에게 닫힌 창을 반환하지 말라고 어떻게 말할 수 있습니까?
또는
창을 닫을 때 창 목록에서 창을 제거하려면 어떻게해야합니까?


업데이트

캡션 막대에서 'x'버튼을 클릭 할 때 CWND 객체가 실제로 닫히지 않고 컨테이너 만 클릭 할 때 CWND 객체가 실제로 닫히는 것을 발견했습니다.
따라서 실제 문제는 창을 실제로 닫는 것 같습니다.
또한 문제를 더 잘 반영하도록 질문을 변경했습니다.

도움이 되었습니까?

해결책

내 업데이트에 설명 된 바와 같이, 도킹 관리자에게 닫힌 창을주는 문제는 판이 실제로 닫히지 않았다는 것입니다. 컨테이너 만 닫혔습니다. PANES 자체는 숨겨져있었습니다.

그래서 창을 정말로 닫으려면 CMDIFrameWndEx 파생 된 메인 프레임 클래스 :

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
}

그리고 두 번째 :

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
}

다른 팁

다음과 같은 MSG 항목을 YOR CMAINFRAM에 추가하십시오.

ON_REGISTERED_MESSAGE(AFX_WM_ON_PRESS_CLOSE_BUTTON,OnClosePane)

Onclosepane은 다음과 같이 보입니다.

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
}

커뮤니티 :

onclosepane은 cbasepane :: Onlbuttondown handler의 중간에서 호출되며, 파괴 창은 코드를 주장 할 것이므로, 메시지를 보내는 대신 메시지 (wm_close)를 게시해야합니다. 여전히 유효 . 그리고 같은 공지의 경우, 우리는 이미 창을 파괴 할 WM_CLOSE를 통해 닫기 때문에 가까이 방지하기 위해 진실을 방지합니다.

WM_RESETMEMBER 메시지는 창자 멤버를 NULL로 재설정하기 위해 등록 된 창 메시지입니다.

IT 구현은 다음과 같습니다.

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

당신은 하나와 같은 맵 입력을 비난해야합니다.

ON_REGISTERED_MESSAGE(WM_RESETMEMBER,OnResetMember)

그리고 다음과 같은 전 세계적으로 메시지를 등록해야합니다.

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

나는 전화를 기대할 것이다 cdockingmanager :: removepanefromdockmanager 작업을 위해 창을 닫을 때.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top