如何识别 QTabWidget 中当前选项卡何时发生变化?

Posted

技术标签:

【中文标题】如何识别 QTabWidget 中当前选项卡何时发生变化?【英文标题】:How to identify when the current tab is changing in a QTabWidget? 【发布时间】:2011-11-29 09:40:38 【问题描述】:

我正在使用QTabWidget,我需要一种方法来在当前选项卡实际发生之前处理它的更改,并且如果满足某些条件可能会取消它。在当前选项卡更改后收到QTabWidget::currentChanged 信号,但是是否有QTabWidget::currentChanging 信号或其他方式来实现我需要的行为?

【问题讨论】:

我不相信有这样的钩子......你必须手动翻转。但这听起来不是一个很好的用户界面选择。为什么不让选项卡的启用状态反映其可用性,而不是尝试“拒绝”对看起来有效的选项卡的点击? doc.qt.nokia.com/latest/qtabwidget.html#setTabEnabled 可以继承 QTabWidget 吗?我没有对此事进行任何研究;这只是一个想法。 我们正是遇到了这个问题,最终选择从头开始编写一个自定义 TabWidget,它会产生一个即将更改的信号并允许对象否决提议的更改。话虽如此,如果可以选择的话,我会选择使用@HostileFork 提出的方法。 @sjwarner 任何让用户感觉自己处于掌控之中的解决方案都比让人觉得它被破坏或无法像他们期望的那样行动的解决方案要好。另一种选择是,与其返回并“撤消”他们看似合法的选项卡单击,不如在目标选项卡上使用QStackedWidget 之类的东西。默认情况下,它可能有一个小部件,上面写着“除非你回到其他一些选项卡,否则这里什么都看不到”。但如果检查通过,它将显示“真实”标签页内容。 doc.qt.nokia.com/latest/qstackedwidget.html#details 就像一个简单的想法,如果满足条件,为什么不禁用标签更改?根本不要让用户更改标签。 【参考方案1】:

就我而言,我这样连接 SIGNAL 和 SLOT:

//check if user clicked at a tab
connect(ui->tabWidget, SIGNAL(currentChanged(int)), this, SLOT(tabSelected()));

tabSelected() 函数中,我检查当前标签索引:

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

    

【讨论】:

【参考方案2】:

我就是这样解决的

void MainWindow::on_tabWidget_currentChanged(int index)

    if (lockTabs) ui->tabWidget->setCurrentIndex(lockedTab);

单击按钮时,我将 lockTabs 设置为 true 并将当前选项卡索引保存到 lockedTab (int)。无论您单击哪个选项卡,它都会将您带回锁定的选项卡。

我同意第一个评论,即禁用标签是更好的方法。这是我禁用标签的解决方案:

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

【讨论】:

【参考方案3】:

在您的标题中,声明:

QWidget *saveTab

创建一个例程tabChanged 拥有currentChanged() 信号的插槽。那么:

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

【讨论】:

【参考方案4】:

使用常规的QTabWidget 并在发出currentChanged 后返回上一个选项卡,如果更改被禁止,则对于用户来说看起来不正确,因为在重新选择前一个选项卡之前新选项卡是可见的,这是由于到QTabWidget 通知标签“已更改”,而不是“即将更改”。

一种选择是创建您自己的QTabWidget。感谢QTabBar,这很明显。

您还需要创建类似QTabWidget 的函数才能“像”QTabWidget 一样使用它,但您需要的函数并不多。

这是QTabWidget 类的示例,其中发出aboutToChangeTab 信号通知选项卡即将更改,可以将allowed 设置为false 以禁止更改选项卡。

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

还有:

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

可以将aboutToChangeTab 连接到插槽 (allowTabChange) 并执行以下操作:

void MyWidget::allowTabChange( QWidget* curTab, QWidget* nextTab, bool* allowed )

    if ( !canChange( curTab, nextTab ) )
        *allowed = false;

【讨论】:

【参考方案5】:

有一个不需要继承 QTabWidget 的事件过滤器的简单解决方案。就我而言,我需要禁用切换到特定选项卡

ui->tabWidget->tabBar()->installEventFilter(this);

然后:

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

在鼠标点击阶段,可以检索当前选定选项卡的索引并准备切换(或取消切换,如我的示例中所做的那样)。

【讨论】:

以上是关于如何识别 QTabWidget 中当前选项卡何时发生变化?的主要内容,如果未能解决你的问题,请参考以下文章

PyQt4:如何/何时从 QTabWidget 的子类发出自定义信号?

Python:如何从 QTabWidget 查询当前选项卡

如何禁用 QTabWidget 中的一个选项卡?

如何在 QTabWidget 中隐藏选项卡并在按下按钮时显示它

在 QTabWidget 中查找选项卡的索引

如何关闭所有选项卡但在 Qt4(QTabWidget)中处于活动状态