I'm using a QTabWidget
and I need a way to handle the change of the current tab before it actually happens, and possibly cancel it if certain conditions are met. The QTabWidget::currentChanged
signal is received after the current tab has changed, but is there a QTabWidget::currentChanging
signal or another way to achieve the behavior I need?

- 5,677
- 4
- 36
- 61

- 363
- 1
- 5
- 14
-
4I don't believe there is such a hook...you would have to manually flip back. But this doesn't sound like a very good user interface choice. Why wouldn't you make the tab's enablement state reflect its availability instead of trying to "reject" a click on a valid-looking tab? http://doc.qt.nokia.com/latest/qtabwidget.html#setTabEnabled – HostileFork says dont trust SE Nov 29 '11 at 09:49
-
Would it be possible to subclass QTabWidget? I haven't done any research on the matter; it's just an idea. – Chris Parton Nov 29 '11 at 09:55
-
We had exactly this problem and eventually chose to write a custom TabWidget from scratch which produced an about-to-change signal and allowed objects to veto proposed changes. Having said that I would have chosen to use the method proposed by @HostileFork if that had been an option. – sam-w Nov 29 '11 at 09:56
-
@sjwarner Any solution that makes the user feel like they're in control is better than one where it feels like it is broken or failing to act like they would expect. Another choice would be that instead of flipping back and "undoing" their seemingly-legitimate tab click, one could use something like a `QStackedWidget` on the target tab. It could by default have a widget in it that said "nothing to see here unless you go back to some other tabs". But if the checks passed it would show the "real" tab page contents. http://doc.qt.nokia.com/latest/qstackedwidget.html#details – HostileFork says dont trust SE Nov 29 '11 at 11:04
-
I have successfully achieved such a behaviour by inheriting QTabWidget. As I do not have access to the code now, I'll wait until I go home to post my code if it's of any interest. – ixM Nov 29 '11 at 12:17
-
1Just as a simple idea why not disable tabs from changing if the condition is met? Don't let the user change tabs at all. – Karlson Mar 29 '12 at 18:58
-
@ixM Could you answer with the solution? thanks! – Javi Carnero Feb 18 '13 at 13:23
5 Answers
In my case, I connect SIGNAL and SLOT like this:
//check if user clicked at a tab
connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSelected()));
and in tabSelected()
function, I check current Tab Index:
void MainWindow::tabSelected(){
if(ui->tabWidget->currentIndex()==0){
// Do something here when user clicked at tab1
}
if(ui->tabWidget->currentIndex()==3){
// Do something here when user clicked at tab4
}
}

- 1,542
- 2
- 26
- 38
This is how I solved it
void MainWindow::on_tabWidget_currentChanged(int index)
{
if (lockTabs) ui->tabWidget->setCurrentIndex(lockedTab);
}
On click of a button, I set lockTabs to true and save the current tab index to lockedTab (int). No matter what tab you click it will just throw you back to the locked tab.
I do agree with the first comment that disabling tabs is the better way tho. This is my solution for disabling tabs:
void MainWindow::lockTabs(int except){
for (int i=0; i<ui->tabWidget->count(); i++) {
if (i!=except) ui->tabWidget->setTabEnabled(i, false);
}
}
void MainWindow::unlockTabs() {
for (int i=0; i<ui->tabWidget->count(); i++) {
ui->tabWidget->setTabEnabled(i, true);
}
}

- 2,873
- 3
- 31
- 56
In your header, declare:
QWidget *saveTab
Create a routine tabChanged
have the slot for the currentChanged()
signal. Then:
void pkgName::tabChanged
//"ask your question"
if "bad reply"
// This is where you'll "set back to your old tab"
ui->tabWidget->setCurrentWidget(savedWidget)
end if
savedWidget = ui->tabWidget-> getCurrentWidget()
// Process

- 20,545
- 20
- 91
- 102

- 81
- 2
There is a simple solution with event filters that doesn't require to subclass QTabWidget. In my case I needed to disable switching to a particular tab
ui->tabWidget->tabBar()->installEventFilter(this);
then:
bool MainWindow::eventFilter(QObject* watched, QEvent* event)
{
if(watched == ui->tabWidget->tabBar())
{
if(event->type() == QEvent::MouseButtonPress)// || event->type() == QEvent::MouseButtonRelease)
{
auto pos = dynamic_cast<QMouseEvent*>(event)->pos();
auto index = ui->tabWidget->tabBar()->tabAt(pos);
if(ui->tabWidget->widget(index) == ui->addButtonTab)
return true; // cancell event
}
}
return QMainWindow::eventFilter(watched, event);
}
At the stage of mouse click it is possible to retrieve index of a currently selected tab and prepare it for being switched(or cancel switching as done in my example).

- 789
- 10
- 28
-
Thanks, andrey.s. This solution works very well. It can stop the tab switching process from the very beginning. – silentspring Jul 30 '23 at 05:42
Using a regular QTabWidget
and flipping back to previous tab after currentChanged
was emitted if change was forbidden does not look right for user as the new tab is made visible before the previous one is re-selected, this is due to QTabWidget
informing the tab "changed", not "is about to change".
One option is to create your own QTabWidget
. Thanks to QTabBar
, this is pretty obvious.
You'll also need to create QTabWidget
like function to use it "like" a QTabWidget
, but there's not so many function you'll need.
Here is an example of QTabWidget
like class with a aboutToChangeTab
signal being emitted informing that tab is about to be changed, one may set allowed
to false
to forbid tab change.
#pragma once
#include <QWidget>
class QTabBar;
class QStackedWidget;
class SmartTabWidget : public QWidget
{
Q_OBJECT
typedef QWidget baseClass;
public:
SmartTabWidget( QWidget* parent );
int addTab(QWidget* page, const QString& label);
int addTab(QWidget* page, const QIcon& icon, const QString& label);
int currentIndex() const;
QWidget* widget( int index );
signals:
void aboutToChangeTab( QWidget* curTab, QWidget* nextTab, bool* allowed );
private slots:
void tryToChangeTab( int index );
private:
QTabBar* m_tab;
QStackedWidget* m_stack;
};
And:
#include "smart_tab_widget.h"
#include <QTabBar>
#include <QStackedWidget>
#include <QVBoxLayout>
#include <QIcon>
SmartTabWidget::SmartTabWidget( QWidget* widget ) :
baseClass( widget )
{
new QVBoxLayout( this );
layout()->setContentsMargins( 0,0,0,0 );
layout()->addWidget( m_tab = new QTabBar(this) );
layout()->addWidget( m_stack = new QStackedWidget(this) );
connect(m_tab, SIGNAL(currentChanged(int)), this, SLOT(tryToChangeTab(int)));
}
int SmartTabWidget::addTab(QWidget* page, const QString& label)
{
return addTab( page, QIcon(), label );
}
int SmartTabWidget::addTab(QWidget* page, const QIcon& icon, const QString & label)
{
m_stack->addWidget( page );
int index = m_tab->addTab( icon, label );
assert( m_stack->count() == index+1 );
return index;
}
int SmartTabWidget::currentIndex() const
{
return m_tab->currentIndex();
}
QWidget* SmartTabWidget::widget( int index )
{
return m_stack->widget( index );
}
void SmartTabWidget::tryToChangeTab( int index )
{
int currentIndex = m_stack->currentIndex();
bool canChange = true;
emit aboutToChangeTab( m_stack->widget( currentIndex ),
m_stack->widget( index ),
&canChange );
if ( canChange )
{
m_stack->setCurrentIndex( index );
}
else
{
// prevent this function to be called again
bool blocked = m_tab->blockSignals( true );
// unselect requested tab as change is not allowed
m_tab->setCurrentIndex( currentIndex );
m_tab->blockSignals( blocked );
}
}
One can connect aboutToChangeTab
to a slot (allowTabChange
) and do something like:
void MyWidget::allowTabChange( QWidget* curTab, QWidget* nextTab, bool* allowed )
{
if ( !canChange( curTab, nextTab ) )
*allowed = false;
}

- 20,821
- 10
- 70
- 151
-
The drawback of this solution is that the user still sees the tab switching before they abort the process, which does not feel very good. The event filter solution proposed by @andrey.s is better, as it interrupts the tab switching from the beginning (i.e. when the mouse press event occurs) – silentspring Jul 30 '23 at 05:41