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

Set the horizontal scroll bar to be on the top of a widget instead of the bottom? (for the pages of a QTabWidget)



  • Hi
    I guess this could seem a bit unusual but I've a problematic use case for my users.
    I'm having a QTabWidget on which I switched the tab position to the West.
    It looks something like this.
    alt text

    The page view can grow both horizontally and vertically.
    When it grows too much horizontally and if I've too many tabs, it's really uncomfortable to scroll the page horizontally: the user needs to first go down to the bottom (where he doesn't see anything on the page anymore) to be able to scroll horizontally...

    A simple solution would be to allow to have the scroll bar on the top of the page.
    Would this be possible in anyway? Or any suggestion for another solution?

    I'm not creating the scroll area. It's done by the QTabWidget. I'm just inserting pages using QTabWidget::insertTab

    PS: I forgot to say, the user can create as many Tabs as he wants...


  • Lifetime Qt Champion

    Hi
    Since there is a QScrolBar widget - i was wondering if you can just place on top in the layout and then connect the
    various signals to keep them in sync.
    Im not sure where the horizontal scrolls come from - as it looks like this with west tabs for me.

    alt text

    The biggest question is that if you can gain access to it or not.

    and then do something like (its 2 views here)
    connect(view1->horizontalScrollBar(), SIGNAL(valueChanged(int)), view2->horizontalScrollBar(), SLOT(setValue(int)));
    connect(view2->horizontalScrollBar(), SIGNAL(valueChanged(int)), view1->horizontalScrollBar(), SLOT(setValue(int)));
    with a standalone QScrollbar



  • @mrjj
    hum that's could be a nice trick indeed!
    but yeah as you noticed, the issue is to get access to the scrollbar.
    it seems to be internal to the QTabWidget...

    Edit: here is a snapshot of the actual issue:
    alt text

    I've to go to the bottom of my Tabs to access the scrollbar of the page. I don't see anymore the headers of my table...
    And we can see that the scrollbar seems to be added by the QTabWidget... for all the pages...


  • Lifetime Qt Champion

    @mbruel
    Hi
    I tried to look into it but i failed at making it show a horizontal scrollbar.
    You say you didnt add an extra scrollArea but i was not albe to get any horz scrollbars.
    Do you resize the actual Tab-Widget to get one ? ( the actual "tab" )

    When you have "the case", could you call
    table->dumpObjectTree();
    (it outputs to Application tab)

    and see if the scrollbar is listed ?

    If yes, we should be able to get hold of it by using FindChild.

    It might be created on the fly so that can be a gotcha as it often means it get deleted again.



  • @mrjj thanks for your help man :)

    Nice, I didn't know that dumpObjectTree... It can be quite useful!!
    Here is my dump.

    Debug: ReprocessingPlantPeriodWidget::  ((null):0, (null))
    Debug:     QStackedWidget::qt_tabwidget_stackedwidget  ((null):0, (null))
    Debug:         QWidget::  ((null):0, (null))
    Debug:         QStackedLayout::  ((null):0, (null))
    Debug:         DateValuesWidget::  ((null):0, (null))
    Debug:             QWidget::qt_scrollarea_viewport  ((null):0, (null))
    Debug:                 QComboBox::  ((null):0, (null))
    Debug:                     QStandardItemModel::  ((null):0, (null))
    Debug:                     QComboBoxPrivateContainer::  ((null):0, (null))
    Debug:                         QBoxLayout::  ((null):0, (null))
    Debug:                         QComboBoxListView::  ((null):0, (null))
    Debug:                             QWidget::qt_scrollarea_viewport  ((null):0, (null))
    Debug:                             QWidget::qt_scrollarea_hcontainer  ((null):0, (null))
    Debug:                                 QScrollBar::  ((null):0, (null))
    Debug:                                 QBoxLayout::  ((null):0, (null))
    Debug:                             QWidget::qt_scrollarea_vcontainer  ((null):0, (null))
    Debug:                                 QScrollBar::  ((null):0, (null))
    Debug:                                 QBoxLayout::  ((null):0, (null))
    Debug:                             QItemSelectionModel::  ((null):0, (null))
    Debug:                             QComboMenuDelegate::  ((null):0, (null))
    Debug:                         QComboBoxPrivateScroller::  ((null):0, (null))
    Debug:                         QComboBoxPrivateScroller::  ((null):0, (null))
    Debug:                 QPushButton::  ((null):0, (null))
    Debug:                 QPushButton::  ((null):0, (null))
    Debug:                 QComboBox::  ((null):0, (null))
    Debug:                     QStandardItemModel::  ((null):0, (null))
    Debug:                     QComboBoxPrivateContainer::  ((null):0, (null))
    Debug:                         QBoxLayout::  ((null):0, (null))
    Debug:                         QComboBoxListView::  ((null):0, (null))
    Debug:                             QWidget::qt_scrollarea_viewport  ((null):0, (null))
    Debug:                             QWidget::qt_scrollarea_hcontainer  ((null):0, (null))
    Debug:                                 QScrollBar::  ((null):0, (null))
    Debug:                                 QBoxLayout::  ((null):0, (null))
    Debug:                             QWidget::qt_scrollarea_vcontainer  ((null):0, (null))
    Debug:                                 QScrollBar::  ((null):0, (null))
    Debug:                                 QBoxLayout::  ((null):0, (null))
    Debug:                             QItemSelectionModel::  ((null):0, (null))
    Debug:                             QComboMenuDelegate::  ((null):0, (null))
    Debug:                         QComboBoxPrivateScroller::  ((null):0, (null))
    Debug:                         QComboBoxPrivateScroller::  ((null):0, (null))
    Debug:                 QWidget::  ((null):0, (null))
    Debug:                     QGridLayout::  ((null):0, (null))
    Debug:                     QPushButton::  ((null):0, (null))
    Debug:                 QComboBox::  ((null):0, (null))
    Debug:                     QStandardItemModel::  ((null):0, (null))
    Debug:                     QComboBoxPrivateContainer::  ((null):0, (null))
    Debug:                         QBoxLayout::  ((null):0, (null))
    Debug:                         QComboBoxListView::  ((null):0, (null))
    Debug:                             QWidget::qt_scrollarea_viewport  ((null):0, (null))
    Debug:                             QWidget::qt_scrollarea_hcontainer  ((null):0, (null))
    Debug:                                 QScrollBar::  ((null):0, (null))
    Debug:                                 QBoxLayout::  ((null):0, (null))
    Debug:                             QWidget::qt_scrollarea_vcontainer  ((null):0, (null))
    Debug:                                 QScrollBar::  ((null):0, (null))
    Debug:                                 QBoxLayout::  ((null):0, (null))
    Debug:                             QItemSelectionModel::  ((null):0, (null))
    Debug:                             QComboMenuDelegate::  ((null):0, (null))
    Debug:                         QComboBoxPrivateScroller::  ((null):0, (null))
    Debug:                         QComboBoxPrivateScroller::  ((null):0, (null))
    Debug:                 QWidget::  ((null):0, (null))
    Debug:                     QGridLayout::  ((null):0, (null))
    Debug:                     QPushButton::  ((null):0, (null))
    Debug:             QStyledItemDelegate::  ((null):0, (null))
    Debug:             QHeaderView::  ((null):0, (null))
    Debug:                 QWidget::qt_scrollarea_viewport  ((null):0, (null))
    Debug:                 QWidget::qt_scrollarea_hcontainer  ((null):0, (null))
    Debug:                     QScrollBar::  ((null):0, (null))
    Debug:                     QBoxLayout::  ((null):0, (null))
    Debug:                 QWidget::qt_scrollarea_vcontainer  ((null):0, (null))
    Debug:                     QScrollBar::  ((null):0, (null))
    Debug:                     QBoxLayout::  ((null):0, (null))
    Debug:                 QItemSelectionModel::  ((null):0, (null))
    Debug:             QHeaderView::  ((null):0, (null))
    Debug:                 QWidget::qt_scrollarea_viewport  ((null):0, (null))
    Debug:                 QWidget::qt_scrollarea_hcontainer  ((null):0, (null))
    Debug:                     QScrollBar::  ((null):0, (null))
    Debug:                     QBoxLayout::  ((null):0, (null))
    Debug:                 QWidget::qt_scrollarea_vcontainer  ((null):0, (null))
    Debug:                     QScrollBar::  ((null):0, (null))
    Debug:                     QBoxLayout::  ((null):0, (null))
    Debug:                 QItemSelectionModel::  ((null):0, (null))
    Debug:             QTableCornerButton::  ((null):0, (null))
    Debug:             QTableModel::  ((null):0, (null))
    Debug:             QItemSelectionModel::  ((null):0, (null))
    Debug:             QWidget::qt_scrollarea_vcontainer  ((null):0, (null))
    Debug:                 QScrollBar::  ((null):0, (null))
    Debug:                 QBoxLayout::  ((null):0, (null))
    Debug:             QWidget::qt_scrollarea_hcontainer  ((null):0, (null))
    Debug:                 QScrollBar::  ((null):0, (null))
    Debug:                 QBoxLayout::  ((null):0, (null))
    Debug:     QTabBar::qt_tabwidget_tabbar  ((null):0, (null))
    Debug:         GroupingsElemWidget::  ((null):0, (null))
    Debug:             QHBoxLayout::  ((null):0, (null))
    Debug:             QLabel::  ((null):0, (null))
    Debug:                 QWidgetTextControl::  ((null):0, (null))
    Debug:                     QTextDocument::  ((null):0, (null))
    Debug:                         QTextDocumentLayout::  ((null):0, (null))
    Debug:                             QTextImageHandler::  ((null):0, (null))
    Debug:                         QTextFrame::  ((null):0, (null))
    Debug:             QPushButton::  ((null):0, (null))
    Debug:         GroupingsAddWidget::  ((null):0, (null))
    Debug:             QComboBox::  ((null):0, (null))
    Debug:                 QStandardItemModel::  ((null):0, (null))
    Debug:                 QComboBoxPrivateContainer::  ((null):0, (null))
    Debug:                     QBoxLayout::  ((null):0, (null))
    Debug:                     QComboBoxListView::  ((null):0, (null))
    Debug:                         QWidget::qt_scrollarea_viewport  ((null):0, (null))
    Debug:                         QWidget::qt_scrollarea_hcontainer  ((null):0, (null))
    Debug:                             QScrollBar::  ((null):0, (null))
    Debug:                             QBoxLayout::  ((null):0, (null))
    Debug:                         QWidget::qt_scrollarea_vcontainer  ((null):0, (null))
    Debug:                             QScrollBar::  ((null):0, (null))
    Debug:                             QBoxLayout::  ((null):0, (null))
    Debug:                         QItemSelectionModel::  ((null):0, (null))
    Debug:                         QComboMenuDelegate::  ((null):0, (null))
    Debug:                     QComboBoxPrivateScroller::  ((null):0, (null))
    Debug:                     QComboBoxPrivateScroller::  ((null):0, (null))
    Debug:             QHBoxLayout::  ((null):0, (null))
    Debug:             QPushButton::  ((null):0, (null))
    Debug:         QLabel::  ((null):0, (null))
    Debug:             QWidgetTextControl::  ((null):0, (null))
    Debug:                 QTextDocument::  ((null):0, (null))
    Debug:                     QTextDocumentLayout::  ((null):0, (null))
    Debug:                         QTextImageHandler::  ((null):0, (null))
    Debug:                     QTextFrame::  ((null):0, (null))
    Debug:         QToolButton::  ((null):0, (null))
    Debug:         QToolButton::  ((null):0, (null))
    Debug:     QDoubleValidator::  ((null):0, (null))
    

    So it is my DateValuesWidget that is having the horizontal QScrollBar. I've just realised that it is not a simple QWidget but it inherits from QTableWidget so inderectly from QAbstractScrollArea. Thus the scrollbar is the one of my DateValuesWidget, not from the Page of the QTabWidget as I was thinking before. My bad...

    So good news, I can access the horizontal scrollbar and try your trick.
    Within my DateValuesWidget I'm able to hide it using setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
    so I can access it using horizontalScrollBar()

    So what you're suggesting is that I instead of adding a DateValuesWidget (QTableWidget) in my page, I use a container QWidget that will have another scrollbar at the Top and the QTableWidget just under. This top scrollbar will be synched with the QTableWidget scrollbar. Am I right?

    Question: I don't want to see the top horizontal scrollbar when it is not needed (i.e: when QTableWidget doesn't have one). How can I test that the horizontal QScrollBar of a QAbstractScrollArea is visible or not?


  • Lifetime Qt Champion

    @mbruel said in Set the horizontal scroll bar to be on the top of a widget instead of the bottom? (for the pages of a QTabWidget):

    So what you're suggesting is that I instead of adding a DateValuesWidget (QTableWidget) in my page, I use a container QWidget that will have another scrollbar at the Top and the QTableWidget just under. This top scrollbar will be synched with the QTableWidget scrollbar. Am I right?

    Yes instead of single DateValuesWidget, then a container widget with a layout and then Scroll bar +
    DateValuesWidget under.

    • Question: I don't want to see the top horizontal scrollbar when it is not needed

    I wish it would have a signal but I dont think they added one :)
    poster here had same issue
    https://forum.qt.io/topic/84137/qscrollarea-signal-or-virtual-function-for-about-to-show-scrollbar
    I ended using rangeChanged to detect it.



  • @mrjj great!
    I'm already trying it. I'm having this container QWidget with a Top scroll bar. I'm trying to do all the connections. I'll post the result when done or ask another question if I'm getting an issue.
    Cheers again!



  • Nice, working like a charm \o/
    @mrjj thanks again! I wouldn't thought we could solve this, that I may have to change the whole design...

    Header:

    class QScrollBar;
    class QAbstractScrollArea;
    class TopScrollBarWidget : public QWidget {
        Q_OBJECT
    
    public:
        TopScrollBarWidget(QAbstractScrollArea *mainWidget, bool hideBottomScrollBar = true, QWidget *parent = nullptr);
        ~TopScrollBarWidget() = default;
    
    public slots:
        void onRangeChanged(int min, int max);
    
    private:
        QScrollBar          *_topHorizontalBar;
        QAbstractScrollArea *_mainWidget;
    };
    

    cpp:

    #include <QVBoxLayout>
    TopScrollBarWidget::TopScrollBarWidget(QAbstractScrollArea *mainWidget, bool hideBottomScrollBar, QWidget *parent) :
        QWidget(parent),
        _topHorizontalBar(new QScrollBar(Qt::Horizontal, this)),
        _mainWidget(mainWidget)
    {
        QVBoxLayout *layout = new QVBoxLayout(this);
        layout->addWidget(_topHorizontalBar);
        layout->addWidget(mainWidget);
        layout->setContentsMargins(0, 0, 0, 2);
    
        QScrollBar *bottomBar = mainWidget->horizontalScrollBar();
        connect(bottomBar,         &QAbstractSlider::valueChanged, _topHorizontalBar, &QAbstractSlider::setValue);
        connect(_topHorizontalBar, &QAbstractSlider::valueChanged, bottomBar,         &QAbstractSlider::setValue);
        connect(bottomBar,         &QScrollBar::rangeChanged,      this,              &TopScrollBarWidget::onRangeChanged);
    
        if (hideBottomScrollBar)
            _mainWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
    }
    
    void TopScrollBarWidget::onRangeChanged(int min, int max)
    {
        _topHorizontalBar->setMinimum(min);
        _topHorizontalBar->setMaximum(max);
    
        _topHorizontalBar->setVisible(min < max); //min = max = 0 if not needed ;)
    }
    

  • Lifetime Qt Champion

    Hi
    You are most welcome. Thank you for sharing the solution as
    the use case might be pretty common and it is indeed not optimal
    having to scroll all the way to the bottom
    to be able to scroll sideways.


Log in to reply