Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Showing the close button for a tab when hovering over the tab



  • I have a QTabWidget which has setTabsCloseable(true); and i have a signal connected to it so it would close the tab.
    But now I'm wondering how do I hide the button when the cursor isn't on the TabBar and how to show it when it is on the tab bar?


  • Moderators

    @Fuchsiaff
    Something like this (UNTESTED):

    class MyTabButton : public QPushButton
    {
    	Q_OBJECT
    
    public:
        MyTabButton(QTabBar* tabBar)
    		: QPushButton(tabbar), m_TabBar(tabbar)
        {
    		m_TabBar->installEventFilter( this );
    		m_OpacityEffect = new QGraphicsOpacityEffect( this );
    			m_OpacityEffect->setOpacity( 0.0 );
    		this->setGraphicsEffect( m_OpacityEffect );
    		
    		connect( this, &MyTabButton::clicked, this, [this]{
    			QMetaObject::invokeMethod(m_TabBar, "tabCloseRequested", Qt::DirectConnection, Q_ARG(int,this->tabIndex())); // trigger tabCloseRequested(int) signal of tabbar. Alternatively trigger a custom signal and react to that
    		});
    		
    		// INIT YOUR BUTTON PROPERTIES (FIXED SIZE, ICON, ETC.) HERE
    	}
    	
    	virtual bool eventFilter(QObject* watched, QEvent* event)
    	{
    		if( watched == m_TabBar )
    		{
    			switch( event->type() )
    			{
    				case QEvent::HoverMove:
    				case QEvent::MouseMove:
    				{
    					QPoint pos = event->type() == QEvent::HoverMove ? static_cast<QHoverEvent*>(event)->pos() : static_cast<QMouseEvent*>(event)->pos();
    					int indexUnderMouse = m_TabBar->tabAt( pos );
    					m_OpacityEffect->setOpacity( indexUnderMouse == this->tabIndex() ? 1.0 : 0.0 );
    				}
    				break;
    				case QEvent::WindowDeactivate:
    				case QEvent::Leave:
    				case QEvent::HoverLeave:
    				{
    					m_OpacityEffect->setOpacity( 0.0 );
    				}
    				break;
    			}
    		}
    		return QPushButton::eventFilter( watched, event );
    	}
    	
    private:
    	int tabIndex() const {
    		for( int i = 0; i < m_TabBar->count(); ++i )
    			if( m_TabBar->tabButton(i,QTabBar::RightSide) == this )
    				return i;
    		return -1;
    	}
    
    	QTabBar*				m_TabBar;
    	QGraphicsOpacityEffect*	m_OpacityEffect;
    };
    
    tabBar->setMouseTracking(true); // might be also work without this
    
    // assign the button to all your closable tabs
    tabbar->setTabButton(index, QTabBar::RightSide, new MyTabButton(tabbar));
    


  • @raven-worx
    Just a question: could most of this be done via a QSS stylesheet :hover etc.?


  • Moderators

    @JonB
    i believe thats not possible. (Styling QTabBar)

    Close buttons can be basically styled:

    QTabBar::close-button {
        image: url(close.png)
        subcontrol-position: left;
    }
    QTabBar::close-button:hover {
        image: url(close-hover.png)
    }
    

    But there is no valid QSS selector to style a close button of a (hovered or even specific) tab:

    QTabBar::tab::close-button {} //sub control selectors must always be placed next to an element (next to another sub.control is not allowed)
    QTabBar::tab::close-button:hover {} // even if that would be valid, the :hover pseudo-state would refer to the button not the tab
    QTabBar::tab:hover::close-button {} // pseudo states must appear at the end of the selector
    

Log in to reply