سؤال

في تطبيق 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 ().

كيف يمكنني إخبار المدير بعدم عودة الأجزاء المغلقة؟
أو
كيف يمكنني إزالة الجزء من قائمة جزء، عندما تكون مغلقة؟


تحديث

لقد قمت بتقسيم أعمق قليلا وجدت، أن كائنات CWND ليست مغلقة بالفعل، عند النقر فوق الزر "x" في شريط التسمية التوضيحية، ولكن حاوياتهم فقط.
لذلك يبدو أن المشكلة الحقيقية هي إغلاق الأجزاء حقا.
لقد غيرت أيضا السؤال لتعكس المشكلة بشكل أفضل.

هل كانت مفيدة؟

المحلول

كما هو موضح في تحديثي، فإن مشكلة مدير الإرساء تعطيني من الأجزاء المغلقة، وكانت الأجزاء غير مغلقة بالفعل. تم إغلاق حاوياتهم فقط؛ وكانت الأجزاء نفسها مخفية فقط.

لذلك لإغلاق الأجزاء حقا، اجلدت الطرق التالية في بلدي 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
}

نصائح أخرى

أضف إلى Yor Cmainfram إدخال MSG مثل ما يلي:

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
}

coution:

يتم استدعاء OnClosepane في وسط CBASEPANE :: Handler Onlbuttondown، ستجعل Desting Wave Code Code الخاص بك، لذلك تحتاج إلى نشر رسالة (WM_CLOSE) بدلا من إرسالها، يعط هذا CBASEPANE :: HOLLER ONLBUTTONDOWN فرصة لإنهاء التنفيذ أثناء التنفيذ لا تزال صالحة . وللطور نفس Rinone أعود حقيقي لمنع الإغلاق لأننا نغلقه بالفعل عبر WM_Close الذي سيدمر النافذة أيضا.

رسالة WM_RESETMEMBER هي رسالة نافذة مسجلة لإعادة تعيين عضو في جزء إلى NULL.

تنفيذه تبدو وكأنها هذه:

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

يجب عليك إدخال MSG خريطة مثل واحد:

ON_REGISTERED_MESSAGE(WM_RESETMEMBER,OnResetMember)

ويجب عليك تسجيل رسالة على مستوى العالم مثل هذا:

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

كنت أتوقع مكالمة CdockingManager :: RemovePanefromdockmanager. عندما تغلق الجزء الخاص بك للقيام بهذه المهمة.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top