I have a QScrollArea that contains a widget that can be dynamically expanded down by adding new elements to its layout. I want to automatically scroll the QScrollArea to the bottom when a new element is added to layout.
// widget.hpp
class MainWidget: public QScrollArea {
Q_OBJECT
public:
explicit MainWidget();
public slots:
void add_new_elem(bool);
private:
void initialize_new_item(void);
QWidget* scrolled_widget;
std::unique_ptr<QVBoxLayout> scrolled_widget_layout;
std::unique_ptr<QPushButton> add_new_item_button;
};
// widget.cpp
#include "widget.hpp"
MainWidget::MainWidget() : QScrollArea() {
scrolled_widget = new QWidget(this);
scrolled_widget->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
scrolled_widget_layout = std::make_unique<QVBoxLayout>(scrolled_widget);
add_new_item_button = std::make_unique<QPushButton>("Add new item!");
add_new_item_button->show();
connect(add_new_item_button.get(), &QPushButton::clicked, this, &MainWidget::add_new_elem);
setWidget(scrolled_widget);
setWidgetResizable(true); // required!
setAlignment(Qt::AlignBottom | Qt::AlignLeft);
}
void MainWidget::initialize_new_item(void) {
auto elem = new Elem();
scrolled_widget_layout->addWidget(elem);
}
void MainWidget::add_new_elem(bool) {
initialize_new_item();
QScrollBar* scrollbar = verticalScrollBar();
scrollbar->setSliderPosition(scrollbar->maximum()); */
}
The issue is that, by the time scrollbar->maximum() is called, the maximum property has not yet been updated (maybe because of the event loop), and the scrollbar is set to an incorrect position.
I searched documentation but did not find signals that indicate geometry changes, and I hate the idea of setting a timer.
How can I make this work?
Use
QAbstractSlider::rangeChanged, but take into account that it will get triggered by any size change. In this case, I used a simpleboolto switch on autoscrolling when an item is added, and switch it off when the scrolling is done: