MFC MDI CtabView hidden / remove navigation controls that are not used

601 Views Asked by At

I have 4 buttons that have no direct application to my program. I would like to hide or remove them. I've searched to find out what they are called...they look like navigation, left/right arrows, next/previous. I can't seem to find what they are called. I have looked on the Microsoft site and looking at the CTabView members doesn't seem to jump out and say "hey, these are what you're looking for"....

Buttons I'd like to remove

I'm hoping it is a relatively easy task. Anyone know how to just "turn them off"?

Thanks.

UPDATE:

I was able to resolve the C4430 mentioned by moving the new function before the existing in OutputWnd.h and that solved the issue in the output pane area where the arrows are now gone. What I forgot to mention is that I have another mechanism AddView that is creating 2 runtime classes and putting those into a tabbed document view. This time, I've been using GetTabControl() to make it pretty, but this also suffers from the same issue, the scroll arrows are now present.

This is what the code looks like that creates the 2 new tabs:

Above this code is the constructor/destructor/headers, nothing else.

IMPLEMENT_DYNCREATE(CTrackView, CTabView)

void CTrackView::OnInitialUpdate()
{

    // add document views   
    AddView(RUNTIME_CLASS(CTrainView), AfxStringID(IDS_TRAIN));
    AddView(RUNTIME_CLASS(CStationView), AfxStringID(IDS_STATION));
    GetTabControl().EnableTabSwap(TRUE);
    GetTabControl().SetLocation(CMFCBaseTabCtrl::Location::LOCATION_BOTTOM);
    GetTabControl().ModifyTabStyle(CMFCTabCtrl::STYLE_3D);
    GetTabControl().SetActiveTabBoldFont(TRUE);

    CTabView::OnInitialUpdate();
    
}

I have tried to comment out CTabView::OnInitialUpdate(); but I know it won't and didn't affect the arrows. I done some searching on the control and I don't see any examples to remove the arrows, I assume another override is in order. I will follow the method shown in the other example, I am looking to see if it can be fixed similar to what has been shown.

Do these share the same CMFCTabCtrl mechanism or is this something different?

Update 2:

The OutputWnd.cpp that the MFC wizard creates has the same issue now that I've modified the tab control, I can't find the right pointer to fix the issue where &tabCtrl()is an unknown identifier. EDIT: This was the issue, I found the fix, see update 3 to see the resolution.

int COutputWnd::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CDockablePane::OnCreate(lpCreateStruct) == -1)
        return -1;

    CRect rectDummy;
    rectDummy.SetRectEmpty();

    // Create User Define tab style:
    int UserTabStyle = AfxGetApp()->GetProfileInt(_T("Settings"), _T("UserTabStyle"), 0); //Get value from registry
    // If the key doesn't exist, UserTableStyle will be 0 or FALSE;

    if (UserTabStyle != FALSE && UserTabStyle <= 8) { // User selected tab style type

        int EnumUserTabStyle = UserTabStyle - 1; // Fix enum if key doesn't exist.

        if (!m_wndTabs.Create(static_cast<CMFCTabCtrl::Style>(EnumUserTabStyle), rectDummy, this, 1))
        {
            TRACE0("Failed to create output tab window\n");
            return -1;      // fail to create
        }
    }
    else { // Default tabs style if Reg key does not exist i.e. new install/program reset
        
        if (!m_wndTabs.Create(CMFCTabCtrl::STYLE_FLAT, rectDummy, this, 1))
            {
                TRACE0("Failed to create output tab window\n");
                return -1;      // fail to create
            }
    }

    // Nicely hack to access protected member
    class CMFCTabCtrlEx : public CMFCTabCtrl
    {
    public:
        void SetDisableScroll() { m_bScroll = FALSE; }
    };

    // One-Liner to Disable navigation control
    ((CMFCTabCtrlEx*)&tabCtrl())->SetDisableScroll();

    // Create output panes:
    const DWORD dwStyle = LBS_NOINTEGRALHEIGHT | WS_CHILD | WS_VISIBLE | WS_HSCROLL | WS_VSCROLL | WS_BORDER;

    if (!m_wndOutputBuild.Create(dwStyle, rectDummy, &m_wndTabs, 2) ||
        !m_wndOutputDebug.Create(dwStyle, rectDummy, &m_wndTabs, 3))
    {
        TRACE0("Failed to create output windows\n");
        return -1;      // fail to create
    }   

    UpdateFonts();

    CString strTabName;
    BOOL bNameValid;

    //Attach list windows to tab:
    bNameValid = strTabName.LoadString(IDS_STATUS_TAB);
    ASSERT(bNameValid);
    m_wndTabs.AddTab(&m_wndOutputBuild, strTabName, (UINT)0);

    bNameValid = strTabName.LoadString(IDS_DEBUG_TAB);
    ASSERT(bNameValid);
    m_wndTabs.AddTab(&m_wndOutputDebug, strTabName, (UINT)1);

    int EnableDebugTab = AfxGetApp()->GetProfileInt(_T("Settings"), _T("EnableDebugTab"), 0); //Get value from registry
    if (EnableDebugTab == FALSE)
    {
        OnOutputtabsDebug(); //Check to see if it should be enabled
    }

    return 0;
}

Update 3:

I found the answer to my unknown identifier, I was trying to call a function that didn't exist. Reformed as such and it works as expected:

// Nicely hack to access protected member
class CMFCTabCtrlEx : public CMFCTabCtrl
{
public:
    void SetDisableScroll() { m_bScroll = FALSE; }
};

// One-Liner to Disable navigation control
((CMFCTabCtrlEx*)&m_wndTabs)->SetDisableScroll();
2

There are 2 best solutions below

3
On BEST ANSWER

I remembered I solved this in the past with an One-liner.
Here a solution (hack) to direct access the m_bScroll Variable in your CTrackView::::OnCreate() function. OnInitialUpdate() comes too late as dxiv explained.

int void CTrackView::::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
   if (CTabView::OnCreate(lpCreateStruct) == -1)
     return -1;

     // add document views   
     AddView(RUNTIME_CLASS(CTrainView), AfxStringID(IDS_TRAIN));
     AddView(RUNTIME_CLASS(CStationView), AfxStringID(IDS_STATION));
     :
     :
   
     // Nicely hack to access protected member
     class CMFCTabCtrlEx : public CMFCTabCtrl
     {
       public:
         void SetDisableScroll() { m_bScroll = FALSE; }
     };

     // One-Liner to Disable navigation control
     ((CMFCTabCtrlEx*)&GetTabControl())->SetDisableScroll();

 }   
7
On

There is no public, documented API to hide those navigation buttons. However, digging into the MFC sources finds that:

  • the arrows are CMFCTabButton m_btnScrollLeft, m_btnScrollRight, m_btnScrollFirst, m_btnScrollLast; in CMFCTabCtrl;

  • they are created in CMFCTabCtrl::OnCreate whenever CMFCTabCtrl::m_bScroll is TRUE;

  • CMFCTabCtrl::m_bScroll is set to TRUE in CMFCTabCtrl::Create if any of the styles STYLE_FLAT, STYLE_FLAT_SHARED_HORZ_SCROLL, STYLE_3D_SCROLLED, STYLE_3D_ONENOTE, STYLE_3D_VS2005, or STYLE_3D_ROUNDED_SCROLL is used.

With that insight, the navigation buttons can be turned off in a couple of ways.

  • By the book: create the CMFCTabCtrl without any of the styles that enable those buttons, which leaves only STYLE_3D available. That loses the navigation buttons, indeed, but the styling of the tab control also becomes different, and the tabs themselves display as small rectangles rather than trapezoids.

  • Undocumented: override the CMFCTabCtrl::m_bScroll and set it to FALSE before the tab window gets created. For example, derive a class CMyTabCtrl to clear m_bScroll.

    class CMyTabCtrl : public CMFCTabCtrl
    {
    protected:
      BOOL PreCreateWindow(CREATESTRUCT &cs) override
      {
        m_bScroll = FALSE;
        return CMFCTabCtrl::PreCreateWindow(cs);
      }
    };
    

    Then instantiate the control as CMyTabCtrl m_wndTabs; instead of CMFCTabCtrl m_wndTabs;.