Professional UI Solutions
Site Map   /  Register
 
 
 

Tab Controls and Tab Containers

How to add a Close button to tabs?

There is a __ETWS_EX_CLOSE_ON_TABS tab window style that, when applied to a CExtTabWnd window, adds a Close button to each tab in the tab window. When the user clicks the Close button in a tab, it is closed. There is another style, ETWS_EX_CLOSE_ON_SELECTED_ONLY, that changes that behavior. When it is applied together with __ETWS_EX_CLOSE_ON_TABS, the Close button is available only for a selected tab. The styles provide you with tabs similar to those in IE 7 and Firefox.

Here is some more info on this topic.

  • You can apply both __ETWS_EX_CLOSE_ON_TABS and ETWS_EX_CLOSE_ON_SELECTED_ONLY styles using the CExtTabWnd::ModifyTabWndStyleEx() method.
  • There is one more style, __ETWI_EX_NO_CLOSE_ON_TAB, that you can use to remove the Close button for a particular tab. The CExtTabWnd::TAB_ITEM_INFO::ModifyItemStyleEx() method allows you to apply this style.
  • If you need to catch clicks on these Close buttons, you can do this by overriding CExtTabWnd::OnTabWndClickedItemCloseButton().
  • MDI tabs with the Close button on a selected tab are demonstrated in the Drawcli sample.

How to hide a tab in a tabbed page container?

You can use the CExtTabPageContainerWnd::PageVisibleSet() method to hide or show any tab item. Please note if the number of tabs is set to 0, the tab strip hides and the page container gets empty.

How to handle the Close and Help buttons on the tab area of the tabbed page container?

You can handle the Close (or/and Help) button by overriding the OnTabWndClickedButton virtual method in a CExtTabPageContainerWnd-derived class. It can be also a class derived from CExtTabPageContainerFlatWnd, CExtTabPageContainerOneNoteWnd or CExtTabPageContainerWhidbeyWnd, which implement style page containers.

Help Button of the Tab Control

The following code shows how to override this method:

class CMyTabPageContainerWnd : public CExtTabPageContainerWnd 
{
public:
    virtual bool OnTabWndClickedButton(
        LONG nHitTest,
        bool bButtonPressed,
        INT nMouseButton, // MK_... values
        UINT nMouseEventFlags
        )
    {
        ASSERT_VALID( this );
        if( nHitTest==__ETWH_BUTTON_CLOSE && !bButtonPressed )
        {
            // place your code here
            return true;
        }
        else if( nHitTest==__ETWH_BUTTON_HELP && !bButtonPressed )
        {
            // place your code here
            return true;
        }
        return 
            CExtTabPageContainerWnd::OnTabWndClickedButton(
                nHitTest,
                bButtonPressed,
                nMouseButton,
                nMouseEventFlags
                );
    }
}; // class CMyTabPageContainerWnd

How to disable selection of a certain page in a tabbed page container?

Create a class derived from CExtTabPageContainerWnd (or from any style class derived from it, e.g. CExtTabPageContainerWhidbeyWnd) and override the OnTabWndSelectionChange virtual method. Please do not forget to call the method of its parent class if you want only to monitor selection events. The method is called twice.

First, the bPreSelectionTest parameter is true and you can return false if you want to skip the page selection (in other words, to disable page selection).

The second time the method is called when the selected tab item is already changed and this parameter is false.

virtual bool CMyTabPageContainerWnd::OnTabWndSelectionChange(
    LONG nOldItemIndex,    
    LONG nNewItemIndex,    
    bool bPreSelectionTest    
    )
{
    bool bRetVal =
        CExtTabPageContainerWnd::OnTabWndSelectionChange(
            nOldItemIndex,
            nNewItemIndex,
            bPreSelectionTest
        );
    if( bRetVal )
    {
        if( bPreSelectionTest )
        {
            /// POINT A:
            /// BEFORE A NEW PAGE IS ACTIVE
            /// (the previous page window is still on the top
            ...
        }   
        else
        {
            /// POINT B:
            /// THE NEW PAGE IS ACTIVE
            /// (it is visible)
            ...
        }
    }
    return bRetVal;
}

How can I know when a tab is clicked?

Create a class derived from CExtTabPageContainerWnd or from any other class derived from CExtTabPageContainerWnd (e.g. CExtTabPageContainerOneNoteWnd) and override the OnTabWndSelectionChange virtual method. Please do not forget to call the method of its parent class if you want only to monitor these events. The method is called twice. First, the bPreSelectionTest parameter is set to true and you can return false if you want to ignore the selection change event. The second time, this parameter is equal to false and the selected tab item is already changed. Here is a sample code snippet:
virtual bool CYourTabPageContainerWnd::OnTabWndSelectionChange(    
	LONG nOldItemIndex,    
	LONG nNewItemIndex,    
	bool bPreSelectionTest    
	)
{
    bool bRetVal =
        CExtTabPageContainerWnd::OnTabWndSelectionChange(
            nOldItemIndex,
            nNewItemIndex,
            bPreSelectionTest
            );
    if( bRetVal )
    {
        if( bPreSelectionTest )
        {
            /// POINT A:
            /// BEFORE A NEW PAGE BECOMES ACTIVE
            /// (the previous page window is still on the top
            ...
        }   
        else
        {
            /// POINT B:
            /// WHEN THE NEW PAGE IS ACTIVATED
            /// (the new page is visible)
            ...
        }
    }
    return bRetVal;
}

How to toggle the visibility of the MDI tab window at run time?

Just override the CExtTabMdiWnd::OnTabWndSyncVisiblilty virtual method. Use a CExtTabMdiWnd-derived class like this:
class CMyExtTabMdiWnd : public CExtTabMdiWnd
{
public:
    CMyExtTabMdiWnd() 
        : CExtTabMdiWnd()
        , m_bVisible( true )
    {
    }
    void SetVisibility(bool bVisible=true)
    {
        m_bVisible = bVisible;
    } 
    bool GetVisibility()
    {
        return m_bVisible;
    } 
protected:    
    bool m_bVisible;
    virtual void OnTabWndSyncVisibility()
    {
        ShowWindow( 
            m_bVisible && ItemGetCount() > 0
                ? SW_SHOW 
                : SW_HIDE 
                );
    }
}; // class CMyExtTabMdiWnd
After calling the CMyExtTabMdiWnd::SetVisibility method, do not forget to call the RecalcLayout method of the frame window.

How to change tab text for an MDI child frame?

The CExtTabMdiWnd class, which implements a tab control window, is designed to manage child frames of an MDI application. By default, the tab text is the same as the title of the corresponding document. If there is no document found for a particular MDI child frame, it is the title of the child frame window that is used. This algorithm is implemented in the CExtTabMdiWnd::OnTabWndQueryItemText() virtual method. So, the default text of a tab item can be changed by overriding this method. For instance, if you need to have the tab text the same as the title of the MDI child frame, use a CExtTabMdiWnd-derived class like as follows:
class CMyTabs : public CExtTabMdiWnd
{
protected:
    virtual __EXT_MFC_SAFE_LPCTSTR OnTabWndQueryItemText(
        const TAB_ITEM_INFO * pTii
        ) const
    {
        HWND hWndMdiChildFrame =
            (HWND) ( pTii->LParamGet() );
        ASSERT( hWndMdiChildFrame != NULL );
        ASSERT( ::IsWindow(hWndMdiChildFrame) );
        static CString g_sLastCaptionTextBuffer;
        int nTextLen =  ::GetWindowTextLength( hWndMdiChildFrame );
        if( nTextLen <= 0 )
            return CExtTabMdiWnd::OnTabWndQueryItemText( pTii );
        int nCaptionTextLen =
            ::GetWindowText(
                hWndMdiChildFrame,
                g_sLastCaptionTextBuffer.GetBuffer( nTextLen + 2 ),
                nTextLen + 1
                );
        g_sLastCaptionTextBuffer.ReleaseBuffer();
        if( nCaptionTextLen <= 0 )
            return CExtTabMdiWnd::OnTabWndQueryItemText( pTii );
        return ((LPCTSTR)g_sLastCaptionTextBuffer);
    }
};

If you have any questions, please visit our forum or contact our technical support team at support@prof-uis.com.