Для работоспособного решения нужен только доступ к полосе прокрутки представления, и его можно легко адаптировать для работы с любым виджетом, использующим полосу прокрутки - не только QAbstractScrollArea
, даже если все виджеты с вертикальной прокруткой, которые предоставляет Qt, действительно происходят из этого виджет (как надо!).
Ключевое замечание, которое допускает такой низкоуровневый подход, заключается в том, что всякий раз, когда контент добавляется к виджету, диапазон вертикальной полосы прокрутки будет изменяться. Таким образом:
Всякий раз, когда изменяется полоса прокрутки range
, мы прокручиваем вниз, если находимся в состоянии viewAtBottom
.
Всякий раз, когда изменяется value
полосы прокрутки, мы обновляем viewAtBottom
, чтобы отразить, находится ли полоса прокрутки в конце (максимуме) своего диапазона.
Это позволяет пользователю свободно прокручивать содержимое без помех, но полоса прокрутки будет «прилипать» к концу диапазона при размещении там.
Хотелось бы, конечно, чтобы был способ наполнить QScrollBar
этим поведением, но нет флага, который бы включил его - по крайней мере, на Qt 5.11.
Следующая функция при вызове QAbstractScrollArea
(т. Е. Любой из видов элементов, таких как QListView
или QListWidget
, QTextEdit
, QTextBrowser
, QPlainTextEdit
и т. Д.), Придаст ей поведение при нахождении внизу при добавлении контента и увеличении диапазона полосы прокрутки.
Нижеследующее работает в Qt 5 и может быть тривиально адаптировано к Qt 4, переопределяя лямбды как слоты в классе помощника. Функция, использующая полосу прокрутки напрямую, также может быть исключена.
// https://github.com/KubaO/stackoverflown/tree/master/questions/qdebug-window-output-52061269
[...]
void rescrollToBottom(QAbstractScrollArea *view) {
static const char kViewAtBottom[] = "viewAtBottom";
auto *scrollBar = view->verticalScrollBar();
Q_ASSERT(scrollBar);
auto rescroller = [scrollBar]() mutable {
if (scrollBar->property(kViewAtBottom).isNull())
scrollBar->setProperty(kViewAtBottom, true);
auto const atBottom = scrollBar->property(kViewAtBottom).toBool();
if (atBottom) scrollBar->setValue(scrollBar->maximum());
};
QObject::connect(scrollBar, &QAbstractSlider::rangeChanged, view, rescroller,
Qt::QueuedConnection);
QObject::connect(scrollBar, &QAbstractSlider::valueChanged, view, [scrollBar] {
auto const atBottom = scrollBar->value() == scrollBar->maximum();
scrollBar->setProperty(kViewAtBottom, atBottom);
});
}
Для полного примера этого кода в действии см. этот ответ .