解決CMFCTabCtrl點“X”無法關閉Tab的方法

來源:互聯網
上載者:User

用VC2008風格做介面,CMFCTabCtrl是選項卡控制類,其中有EnableActiveTabCloseButton(BOOL)方法可以顯示關閉按鈕"X",但是點擊以後無反應,再次點擊程式就會崩潰,這是MFC的一個bug,詳見此討論帖:http://topic.csdn.net/u/20110120/12/35f605e1-f94f-4ff9-a470-d36124816b2b.html

 

此帖中comey樓主解決了問題,他是這樣做的:

 

1,建立一個類繼承自CMFCTabCtrl,即class CMyMFCTabCtrl : public CMFCTabCtrl

2,重寫OnCommand函數:

BOOL CMyMFCTabCtrl::OnCommand(WPARAM wParam, LPARAM lParam)
{
        // TODO: 在此添加專用代碼和/或調用基類
        if ((HWND)lParam == m_btnClose.GetSafeHwnd())
        {
                int nTab = GetActiveTab();
                if (nTab >= 0)
                {
                        RemoveTab(nTab);
                }
                return true;
        }
        return CMFCTabCtrl::OnCommand(wParam, lParam);
}

(這段如果comey兄覺得不合適請提醒)

 

但是我運行後,發現有問題:

1,點擊“X”後無法響應次函數。

2,通過點擊選項本身進入此函數,發現m_btnClose為空白,查了一下代碼,發現:

 

只用在m_bScroll為真的情況下才會建立m_btnClose,代碼如下:

 

 

int CMFCTabCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)

{

if (CMFCBaseTabCtrl::OnCreate(lpCreateStruct) == -1)

return -1;

 

CRect rectDummy(0, 0, 0, 0);

 

if (m_bScroll)

{

//-----------------------

// Create scroll buttons:

//-----------------------

if (m_bFlat)

{

m_btnScrollFirst.Create(_T(""), WS_CHILD | WS_VISIBLE, rectDummy, this, (UINT) -1);

m_btnScrollFirst.SetStdImage(CMenuImages::IdArrowFirst);

m_btnScrollFirst.m_bDrawFocus = FALSE;

m_btnScrollFirst.m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT;

m_lstButtons.AddTail(m_btnScrollFirst.GetSafeHwnd());

}

 

m_btnScrollLeft.Create(_T(""), WS_CHILD | WS_VISIBLE, rectDummy, this, (UINT) -1);

m_btnScrollLeft.SetStdImage(m_bFlat ? CMenuImages::IdArrowLeftLarge : CMenuImages::IdArrowLeftTab3d,

m_bIsOneNoteStyle || m_bIsVS2005Style || m_bFlat ? CMenuImages::ImageBlack : CMenuImages::ImageDkGray,

m_bFlat ?(CMenuImages::IMAGES_IDS) 0 : CMenuImages::IdArrowLeftDsbldTab3d);

m_btnScrollLeft.m_bDrawFocus = FALSE;

m_btnScrollLeft.m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT;

 

if (!m_bIsOneNoteStyle && !m_bIsVS2005Style)

{

m_btnScrollLeft.SetAutorepeatMode(50);

}

 

m_lstButtons.AddTail(m_btnScrollLeft.GetSafeHwnd());

 

m_btnScrollRight.Create(_T(""), WS_CHILD | WS_VISIBLE, rectDummy, this, (UINT) -1);

m_btnScrollRight.SetStdImage( m_bFlat ? CMenuImages::IdArrowRightLarge : CMenuImages::IdArrowRightTab3d,

m_bIsOneNoteStyle || m_bIsVS2005Style || m_bFlat ? CMenuImages::ImageBlack : CMenuImages::ImageDkGray,

m_bFlat ?(CMenuImages::IMAGES_IDS) 0 : CMenuImages::IdArrowRightDsbldTab3d);

m_btnScrollRight.m_bDrawFocus = FALSE;

m_btnScrollRight.m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT;

 

if (!m_bIsOneNoteStyle && !m_bIsVS2005Style)

{

m_btnScrollRight.SetAutorepeatMode(50);

}

 

m_lstButtons.AddTail(m_btnScrollRight.GetSafeHwnd());

 

if (m_bFlat)

{

m_btnScrollLast.Create(_T(""), WS_CHILD | WS_VISIBLE, rectDummy, this, (UINT) -1);

m_btnScrollLast.SetStdImage(CMenuImages::IdArrowLast);

m_btnScrollLast.m_bDrawFocus = FALSE;

m_btnScrollLast.m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT;

m_lstButtons.AddTail(m_btnScrollLast.GetSafeHwnd());

}

 

m_btnClose.Create(_T(""), WS_CHILD | WS_VISIBLE, rectDummy, this, (UINT) -1);

m_btnClose.SetStdImage(CMenuImages::IdClose, m_bIsOneNoteStyle || m_bIsVS2005Style || m_bFlat ? CMenuImages::ImageBlack : CMenuImages::ImageDkGray);

m_btnClose.m_bDrawFocus = FALSE;

m_btnClose.m_nFlatStyle = CMFCButton::BUTTONSTYLE_FLAT;

m_lstButtons.AddTail(m_btnClose.GetSafeHwnd());

 

if (!m_bFlat && m_bScroll)

{

CString str;

 

ENSURE(str.LoadString(IDS_AFXBARRES_CLOSEBAR));

m_btnClose.SetTooltip(str);

 

ENSURE(str.LoadString(IDP_AFXBARRES_SCROLL_LEFT));

m_btnScrollLeft.SetTooltip(str);

 

ENSURE(str.LoadString(IDP_AFXBARRES_SCROLL_RIGHT));

m_btnScrollRight.SetTooltip(str);

}

}

 

if (m_bSharedScroll)

{

m_wndScrollWnd.Create(WS_CHILD | WS_VISIBLE | SBS_HORZ, rectDummy, this, (UINT) -1);

}

 

if (m_bFlat)

{

//---------------------

// Create active brush:

//---------------------

m_brActiveTab.CreateSolidBrush(GetActiveTabColor());

}

else

{

//---------------------------------------

// Text may be truncated. Create tooltip.

//---------------------------------------

if (CTooltipManager::CreateToolTip(m_pToolTip, this, AFX_TOOLTIP_TYPE_TAB))

{

m_pToolTip->SetWindowPos(&wndTop, -1, -1, -1, -1, SWP_NOMOVE | SWP_NOACTIVATE | SWP_NOSIZE);

}

}

 

CTooltipManager::CreateToolTip(m_pToolTipClose, this, AFX_TOOLTIP_TYPE_TAB);

 

if (afxGlobalData.m_hcurStretch == NULL)

{

afxGlobalData.m_hcurStretch = AfxGetApp()->LoadCursor(AFX_IDC_HSPLITBAR);

}

 

if (afxGlobalData.m_hcurStretchVert == NULL)

{

afxGlobalData.m_hcurStretchVert = AfxGetApp()->LoadCursor(AFX_IDC_VSPLITBAR);

}

 

SetTabsHeight();

return 0;

}

 

 

所以我使用樓主comey的方法失敗。

通過跟蹤OnLButtonDown方法,在基類中,會做這樣的處理

 

void CMFCBaseTabCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
m_bWindowPosChanged = FALSE;

CWnd::OnLButtonDown(nFlags, point);

if (m_rectCloseButton.PtInRect(point))//會進入這裡
{
m_bTabCloseButtonPressed = TRUE;                                     //改變了這個標誌位
RedrawWindow(m_rectCloseButton);   
return;                                                                                    //然後return掉
}

 

返回上一層,在CMFCTabCtrl中:

 

void CMFCTabCtrl::OnLButtonDown(UINT nFlags, CPoint point)

{

if (m_rectTabSplitter.PtInRect(point))

{

m_bTrackSplitter = TRUE;

SetCapture();

return;

}

 

if (m_ResizeMode != RESIZE_NO && m_rectResize.PtInRect(point))

{

RECT rectBounds;

LRESULT lResult = GetParent()->SendMessage(AFX_WM_GETDRAGBOUNDS, (WPARAM)(LPVOID)this, (LPARAM)(LPVOID) &rectBounds);

m_rectResizeBounds = rectBounds;

 

if (lResult != 0 && !m_rectResizeBounds.IsRectEmpty())

{

m_bResize = TRUE;

SetCapture();

m_rectResizeDrag = m_rectResize;

ClientToScreen(m_rectResizeDrag);

 

CRect rectEmpty;

rectEmpty.SetRectEmpty();

 

DrawResizeDragRect(m_rectResizeDrag, rectEmpty);

return;

}

}

 

if (IsMDITabGroup())

{

int nTab = GetTabFromPoint(point);

if (nTab == m_iActiveTab)

{

ActivateMDITab(nTab);

}

}

 

CMFCBaseTabCtrl::OnLButtonDown(nFlags, point);//這裡返回

 

if (!m_bReadyToDetach)//進入這裡

{

CWnd* pWndTarget = FindTargetWnd(point);

if (pWndTarget != NULL)//pWndTarget為空白,導致訊息發不出去

{

ASSERT_VALID(pWndTarget);

 

MapWindowPoints(pWndTarget, &point, 1);

pWndTarget->SendMessage(WM_LBUTTONDOWN, nFlags, MAKELPARAM(point.x, point.y));

}

}

}

 

 

於是我只能在CMyTabCtrl中響應OnLButtonDown訊息,把基類的訊息覆蓋,代碼如下:

 

void CMyTabCtrl::OnLButtonDown(UINT nFlags, CPoint point)

{

// TODO: 在此添加訊息處理常式代碼和/或調用預設值

CMFCTabCtrl::OnLButtonDown(nFlags, point);//先執行基類操作,否則會丟失視窗焦點

 

if (m_rectCloseButton.PtInRect(point))

{

int nTab = GetActiveTab();

if (nTab >= 0)

{

CWnd* pWnd = GetTabWnd (nTab);

pWnd->DestroyWindow ();

delete pWnd;

RemoveTab(nTab);//先刪除視窗,再刪除tab

}

}

 

}

 

 

在我這裡實現了想要的效果,即可以關閉tab,有不合理的地方或有更好的方法歡迎提出。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.