使用 Base Class 对象调用 Dervied Class 函数
Call Dervied Class function Using Base Class object
我正在尝试绘制 CMFCRibbonTab
一个略微不同的图,其中文本的位置稍微高一点。
为了实现这一点,我创建了一个名为 DCRibbonTab
的派生 class,它扩展了 CMFCRibbonTab
并重写了 virtual void OnDraw(CDC * pDC)
函数,如下所示:
#pragma once
#include "StdAfx.h"
class DCRibbonTab : public CMFCRibbonTab
{
public:
DCRibbonTab ();
virtual ~DCRibbonTab ();
virtual void OnDraw(CDC* pDC);
};
DCRibbonTab::~DCRibbonTab()
{
}
void DCRibbonTab::OnDraw(CDC * pDC)
{
CMFCRibbonTab::OnDraw(pDC);
ASSERT_VALID(this);
ASSERT_VALID(m_pParent);
ASSERT_VALID(m_pParent->GetParentRibbonBar());
if (m_rect.IsRectEmpty())
{
return;
}
COLORREF clrText = CMFCVisualManager::GetInstance()->OnDrawRibbonCategoryTab(pDC, this, m_pParent->IsActive() || GetDroppedDown() != NULL);
COLORREF clrTextOld = pDC->SetTextColor(clrText);
CRect rectTab = m_rect;
CRect rectTabText = m_rect;
pDC->DrawText(L"test", rectTabText, DT_CALCRECT | DT_SINGLELINE | DT_VCENTER);
const int cxTabText = rectTabText.Width();
const int cxTabTextMargin = max(4, (rectTab.Width() - cxTabText) / 2);
rectTab.DeflateRect(cxTabTextMargin, 0);
//rectTab.top += nPanelMarginTop;
pDC->DrawText(GetParentCategory()->GetName(), rectTab, DT_SINGLELINE | DT_VCENTER);
pDC->SetTextColor(clrTextOld);
}
为了能够调用 DCRibbonTab
的新 virtual void OnDraw(CDC * pDC)
,我必须重写 CMFCRibbonBar
Class 的 void OnPaint()
,如下所示:
void DCRibbonBar::OnPaint()
{
CMFCRibbonBar::OnPaint();
CPaintDC dc(this); // device context for painting
int i = 0;
CMemDC memDC(dc, this);
CDC* pDC = &memDC.GetDC();
for (i = 0; i < (int)m_arCategories.GetSize(); i++)
{
CMFCRibbonCategory* pCategory = m_arCategories[i];
ASSERT_VALID(pCategory);
if (pCategory->IsVisible())
{
CMFCRibbonTab * CurrentTab = pCategory->GetTab();
//Need to Call DCRibbonTab OnDraw function using CMFCRibbonTab object CurrentTab
}
}
}
但是,我似乎无法实现的是调用派生的 class DCRibbonTab
virtual void OnDraw(CDC * pDC)
使用基础 class 对象,其中CMFCRibbonTab
对象。
那么,如何从基础 class 对象 CMFCRibbonTab
调用派生 class 函数 DCRibbonTab
?
class DCRibbonTab : public CMFCRibbonTab
{
public:
DCRibbonTab ();
virtual ~DCRibbonTab ();
void OnDraw(CDC* pDC) override;
};
如果您的 OnDraw() 方法版本实际上并未覆盖基础 class 中定义的方法,则此版本应提供明确的错误消息。如果您看到该错误,您就知道您需要仔细检查您是否与基 class 中的函数签名完全匹配,当然还要确认该函数在基 'virtual' 中声明。
如果添加 'override' 后没有出现错误,那么调用正确的版本应该很简单:
CurrentTab->OnDraw(pDC);
经过一些研究,我找到了解决方案,使用函数重载和运行时多态性。
这是解决方案的源代码:
class DCRibbonTab : public CMFCRibbonTab
{
public:
DCRibbonTab();
virtual ~DCRibbonTab();
void OnDraw(CDC* pDC, BOOL Redraw);
};
static const int nPanelMarginTop = 3;
// DCRibbonTab
DCRibbonTab:: DCRibbonTab ()
{
}
DCRibbonTab::~ DCRibbonTab ()
{
}
void DCRibbonTab::OnDraw(CDC* pDC, BOOL Redraw)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
ASSERT_VALID(m_pParent);
ASSERT_VALID(m_pParent->GetParentRibbonBar());
if (m_rect.IsRectEmpty())
{
return;
}
COLORREF clrText = CMFCVisualManager::GetInstance()->OnDrawRibbonCategoryTab(pDC, this, m_pParent->IsActive() || GetDroppedDown() != NULL);
COLORREF clrTextOld = pDC->SetTextColor(clrText);
CRect rectTab = m_rect;
CRect rectTabText = m_rect;
pDC->DrawText(m_pParent->GetName(), rectTabText, DT_CALCRECT | DT_SINGLELINE | DT_TOP);
const int cxTabText = rectTabText.Width();
const int cxTabTextMargin = max(4, (rectTab.Width() - cxTabText) / 2);
rectTab.DeflateRect(cxTabTextMargin, 0);
rectTab.top += nPanelMarginTop;
pDC->DrawText(m_pParent->GetName(), rectTab, DT_SINGLELINE | DT_TOP);
pDC->SetTextColor(clrTextOld);
}
void DCRibbonBar::OnPaint()
{
CPaintDC dc(this); // device context for painting
int i = 0;
CMemDC memDC(dc, this);
CDC* pDC = &memDC.GetDC();
CRect rectClip;
dc.GetClipBox(rectClip);
CRgn rgnClip;
if (!rectClip.IsRectEmpty())
{
rgnClip.CreateRectRgnIndirect(rectClip);
pDC->SelectClipRgn(&rgnClip);
}
pDC->SetBkMode(TRANSPARENT);
CRect rectClient;
GetClientRect(rectClient);
OnFillBackground(pDC, rectClient);
CFont* pOldFont = pDC->SelectObject(GetFont());
ENSURE(pOldFont != NULL);
// Draw tabs:
CRect rectTabs = rectClient;
rectTabs.top = m_rectCaption.IsRectEmpty() ? rectClient.top : m_rectCaption.bottom;
rectTabs.bottom = rectTabs.top + m_nTabsHeight;
COLORREF clrTextTabs = CMFCVisualManager::GetInstance()->OnDrawRibbonTabsFrame(pDC, this, rectTabs);
for (i = 0; i < (int)m_arCategories.GetSize(); i++)
{
CMFCRibbonCategory* pCategory = m_arCategories[i];
ASSERT_VALID(pCategory);
if (pCategory->IsVisible())
{
DCRibbonTab *TempVnRibbonTab = new DCRibbonTab ();
CMFCRibbonTab * TempMFCRibbonTab = pCategory->GetTab();
TempDCRibbonTab = (DCRibbonTab*)TempMFCRibbonTab;
TempDCRibbonTab->OnDraw(pDC, TRUE);
}
}
// Draw elements on right of tabs:
COLORREF clrTextOld = (COLORREF)-1;
if (clrTextTabs != (COLORREF)-1)
{
clrTextOld = pDC->SetTextColor(clrTextTabs);
}
pDC->SelectObject(pOldFont);
pDC->SelectClipRgn(NULL);
}
我正在尝试绘制 CMFCRibbonTab
一个略微不同的图,其中文本的位置稍微高一点。
为了实现这一点,我创建了一个名为 DCRibbonTab
的派生 class,它扩展了 CMFCRibbonTab
并重写了 virtual void OnDraw(CDC * pDC)
函数,如下所示:
#pragma once
#include "StdAfx.h"
class DCRibbonTab : public CMFCRibbonTab
{
public:
DCRibbonTab ();
virtual ~DCRibbonTab ();
virtual void OnDraw(CDC* pDC);
};
DCRibbonTab::~DCRibbonTab()
{
}
void DCRibbonTab::OnDraw(CDC * pDC)
{
CMFCRibbonTab::OnDraw(pDC);
ASSERT_VALID(this);
ASSERT_VALID(m_pParent);
ASSERT_VALID(m_pParent->GetParentRibbonBar());
if (m_rect.IsRectEmpty())
{
return;
}
COLORREF clrText = CMFCVisualManager::GetInstance()->OnDrawRibbonCategoryTab(pDC, this, m_pParent->IsActive() || GetDroppedDown() != NULL);
COLORREF clrTextOld = pDC->SetTextColor(clrText);
CRect rectTab = m_rect;
CRect rectTabText = m_rect;
pDC->DrawText(L"test", rectTabText, DT_CALCRECT | DT_SINGLELINE | DT_VCENTER);
const int cxTabText = rectTabText.Width();
const int cxTabTextMargin = max(4, (rectTab.Width() - cxTabText) / 2);
rectTab.DeflateRect(cxTabTextMargin, 0);
//rectTab.top += nPanelMarginTop;
pDC->DrawText(GetParentCategory()->GetName(), rectTab, DT_SINGLELINE | DT_VCENTER);
pDC->SetTextColor(clrTextOld);
}
为了能够调用 DCRibbonTab
的新 virtual void OnDraw(CDC * pDC)
,我必须重写 CMFCRibbonBar
Class 的 void OnPaint()
,如下所示:
void DCRibbonBar::OnPaint()
{
CMFCRibbonBar::OnPaint();
CPaintDC dc(this); // device context for painting
int i = 0;
CMemDC memDC(dc, this);
CDC* pDC = &memDC.GetDC();
for (i = 0; i < (int)m_arCategories.GetSize(); i++)
{
CMFCRibbonCategory* pCategory = m_arCategories[i];
ASSERT_VALID(pCategory);
if (pCategory->IsVisible())
{
CMFCRibbonTab * CurrentTab = pCategory->GetTab();
//Need to Call DCRibbonTab OnDraw function using CMFCRibbonTab object CurrentTab
}
}
}
但是,我似乎无法实现的是调用派生的 class DCRibbonTab
virtual void OnDraw(CDC * pDC)
使用基础 class 对象,其中CMFCRibbonTab
对象。
那么,如何从基础 class 对象 CMFCRibbonTab
调用派生 class 函数 DCRibbonTab
?
class DCRibbonTab : public CMFCRibbonTab
{
public:
DCRibbonTab ();
virtual ~DCRibbonTab ();
void OnDraw(CDC* pDC) override;
};
如果您的 OnDraw() 方法版本实际上并未覆盖基础 class 中定义的方法,则此版本应提供明确的错误消息。如果您看到该错误,您就知道您需要仔细检查您是否与基 class 中的函数签名完全匹配,当然还要确认该函数在基 'virtual' 中声明。
如果添加 'override' 后没有出现错误,那么调用正确的版本应该很简单:
CurrentTab->OnDraw(pDC);
经过一些研究,我找到了解决方案,使用函数重载和运行时多态性。 这是解决方案的源代码:
class DCRibbonTab : public CMFCRibbonTab
{
public:
DCRibbonTab();
virtual ~DCRibbonTab();
void OnDraw(CDC* pDC, BOOL Redraw);
};
static const int nPanelMarginTop = 3;
// DCRibbonTab
DCRibbonTab:: DCRibbonTab ()
{
}
DCRibbonTab::~ DCRibbonTab ()
{
}
void DCRibbonTab::OnDraw(CDC* pDC, BOOL Redraw)
{
ASSERT_VALID(this);
ASSERT_VALID(pDC);
ASSERT_VALID(m_pParent);
ASSERT_VALID(m_pParent->GetParentRibbonBar());
if (m_rect.IsRectEmpty())
{
return;
}
COLORREF clrText = CMFCVisualManager::GetInstance()->OnDrawRibbonCategoryTab(pDC, this, m_pParent->IsActive() || GetDroppedDown() != NULL);
COLORREF clrTextOld = pDC->SetTextColor(clrText);
CRect rectTab = m_rect;
CRect rectTabText = m_rect;
pDC->DrawText(m_pParent->GetName(), rectTabText, DT_CALCRECT | DT_SINGLELINE | DT_TOP);
const int cxTabText = rectTabText.Width();
const int cxTabTextMargin = max(4, (rectTab.Width() - cxTabText) / 2);
rectTab.DeflateRect(cxTabTextMargin, 0);
rectTab.top += nPanelMarginTop;
pDC->DrawText(m_pParent->GetName(), rectTab, DT_SINGLELINE | DT_TOP);
pDC->SetTextColor(clrTextOld);
}
void DCRibbonBar::OnPaint()
{
CPaintDC dc(this); // device context for painting
int i = 0;
CMemDC memDC(dc, this);
CDC* pDC = &memDC.GetDC();
CRect rectClip;
dc.GetClipBox(rectClip);
CRgn rgnClip;
if (!rectClip.IsRectEmpty())
{
rgnClip.CreateRectRgnIndirect(rectClip);
pDC->SelectClipRgn(&rgnClip);
}
pDC->SetBkMode(TRANSPARENT);
CRect rectClient;
GetClientRect(rectClient);
OnFillBackground(pDC, rectClient);
CFont* pOldFont = pDC->SelectObject(GetFont());
ENSURE(pOldFont != NULL);
// Draw tabs:
CRect rectTabs = rectClient;
rectTabs.top = m_rectCaption.IsRectEmpty() ? rectClient.top : m_rectCaption.bottom;
rectTabs.bottom = rectTabs.top + m_nTabsHeight;
COLORREF clrTextTabs = CMFCVisualManager::GetInstance()->OnDrawRibbonTabsFrame(pDC, this, rectTabs);
for (i = 0; i < (int)m_arCategories.GetSize(); i++)
{
CMFCRibbonCategory* pCategory = m_arCategories[i];
ASSERT_VALID(pCategory);
if (pCategory->IsVisible())
{
DCRibbonTab *TempVnRibbonTab = new DCRibbonTab ();
CMFCRibbonTab * TempMFCRibbonTab = pCategory->GetTab();
TempDCRibbonTab = (DCRibbonTab*)TempMFCRibbonTab;
TempDCRibbonTab->OnDraw(pDC, TRUE);
}
}
// Draw elements on right of tabs:
COLORREF clrTextOld = (COLORREF)-1;
if (clrTextTabs != (COLORREF)-1)
{
clrTextOld = pDC->SetTextColor(clrTextTabs);
}
pDC->SelectObject(pOldFont);
pDC->SelectClipRgn(NULL);
}