Дневник Шестеро Михаила

Apr. 19th, 2014

02:51 am - Qt: сокрытие вкладок в QTabWidget

В стандартном виджете для организации вкадок в Qt нет возможности сокрытия отдельных вкладок (show/hide). Интернете не нашёл решения – предлагают сложные пути: временно удалять вкладки или переделывать виджет.

Кажется мне удалось найти простое решение, оно годится если вы не используйте «задисейбленные» («серые», «режим только-чтение») вкладки (disabled). Кстати, для сокрытых вкладок это и не имеет смысла.

Идея в том, что бы ставить режим disabled вкладкам, которые надо скрыть, а для маскировки вкладок использовать приём задание стиля с нулевым размером вкладки. Причём при установке режима disabled виджет автоматически переключит активную вкладку.

Нужный стиль устанавливается так:

#include "qtesttabwidget.h"

#include <QTabBar>

QTestTabWidget::QTestTabWidget() // наследник QTabWidget
{
    setStyleSheet();
}

void QTestTabWidget::setStyleSheet()
{
    tabBar()->setStyleSheet(
        "QTabBar::tab:disabled { width: 0; height: 0; right: 1px; }" //  ??? border-style: none; margin-left: 1px;
    );
}
У меня чуть-чуть кривовато выглядит последняя граница последней видимой вкладки, если она не активная и если скрыть самую последнюю. Вероятно тут можно как-то добиться идеального отображения и в этом случае поколдовав с полями, смещениями итд в стиле. Если кто разберётся с этим — пожалуйста, отправьте мне результат!
Состояние «:disabled» вроде не документировано для QTabBar::tab, однако у меня в Qt 4.5.0 это работает, думаю, и в новых версиях тоже должно.

Вот тестовая программа (код класса главного окна QMainWindow), которая динамически скрывает/показывает вкладки:
#include "mainwindow.h"

#include <QCheckBox>
#include <QVBoxLayout>
#include <QHBoxLayout>

#include <QLabel>
#include <QTabBar>


MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    QWidget* w = new QWidget(this);
    QVBoxLayout* vl = new QVBoxLayout( w );
    QHBoxLayout* hl = new QHBoxLayout;
    vl->addLayout( hl );
    vl->addWidget( m_tabs = new QTestTabWidget );

    for (int i=0; i<3; i++)
    {
        const QString num = QString::number(i+1);
        QCheckBox* ch = new QCheckBox( QString("Show tab#")+num );
        ch->setChecked(true);
        hl->addWidget(ch);
        m_map.insert( ch, m_tabs->addTab(new QLabel( QString("Label ")+num ), QString("tab#")+num ) );
        // ^ QMap<QCheckBox*,int> m_map;
        connect( ch, SIGNAL(stateChanged(int)), this, SLOT(stateChanged(int)) );
    }

    setCentralWidget( w );
}

void MainWindow::stateChanged( int state )
{
    QCheckBox *p = qobject_cast<QCheckBox*>( sender() );
    if ( p==NULL||!m_map.contains(p) )
        return;

    m_tabs->setTabEnabled( m_map[p], state!=Qt::Unchecked );
    m_tabs->setStyleSheet();
}

PS Наткнулся на одну "кривость": если использовать виджеты на вкладках (в моём случае это раскрывающийся список на том месте, где обычно кнопка закрытия вкладки):
QComboBox *ysel = new YearInTabComboBox( years ); // наследник QComboBox
tabBar()->setTabButton(num, QTabBar::RightSide, ysel); // установка виджета во вкладку num справа от текста
то при сокрытии вкладки этим методом эти виджеты у меня должным образом не скрываются и могут образовать "стопку" уложившись рядом. (С кнопками закрытия, наверное, будет то же самое). Впрочем, на сколько я представляю, во-первых, мало кто ставит виджеты во вкладки, а во-вторых это можно обойти, дополнительно скрывая и показывая такие виджеты на соответствующих вкладках обычным способом (методами show/hide).

Tags: , , , ,
Current Mood: [mood icon] satisfied