Search code examples
c++mfcribbon

Call Dervied Class function Using Base Class object


I’m trying to draw CMFCRibbonTab a with slightly small difference in which the text is a positionned a little bit higher.

To achieve that I’ve created a derived class called DCRibbonTab that extends CMFCRibbonTab and rewritten virtual void OnDraw(CDC * pDC) function as the following :

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

To be able to call the new virtual void OnDraw(CDC * pDC) of the DCRibbonTab I had to override the void OnPaint() of the CMFCRibbonBar Class as the following :

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

        }
    }
}

However, what I don’t seem to be able to achieve is to call the derived class DCRibbonTab virtual void OnDraw(CDC * pDC) using the base class object in which is CMFCRibbonTab object.

So, how can I call derived class function DCRibbonTab from base class object CMFCRibbonTab?


Solution

  • After some research, I was able to find the solution, using function overloading and Runtime polymorphism. Here is the source code for the solution:

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