Как автоматически прокрутить QTextEdit, QAbstractItemView, QAbstractScrollArea и т. Д. Вниз? - PullRequest
0 голосов
/ 29 августа 2018

Часто запрашиваемое поведение заключается в том, чтобы выводить виджет «log» вниз, если пользователь не прокручивал в другом месте. Существуют специфичные для виджетов решения, то есть специфичные для QTextEdit или QListView и т. Д., Но они всегда требуют изменений в коде пользователя - и код пользователя уже делает правильные вещи и добавляет данные в модель, используемую Посмотреть. Изменение этого кода будет чрезмерно привязывать его к деталям представления и, следовательно, будет иметь неприятный запах при разработке программного обеспечения.

То, что можно пожелать, таким образом, - это способ изменения поведения самого виджета без изменения пользовательского кода. Более того - возможно, есть способ, который будет работать в большинстве классов, производных от QAbstractScrollArea?

1 Ответ

0 голосов
/ 29 августа 2018

Для работоспособного решения нужен только доступ к полосе прокрутки представления, и его можно легко адаптировать для работы с любым виджетом, использующим полосу прокрутки - не только QAbstractScrollArea, даже если все виджеты с вертикальной прокруткой, которые предоставляет Qt, действительно происходят из этого виджет (как надо!).

Ключевое замечание, которое допускает такой низкоуровневый подход, заключается в том, что всякий раз, когда контент добавляется к виджету, диапазон вертикальной полосы прокрутки будет изменяться. Таким образом:

  1. Всякий раз, когда изменяется полоса прокрутки range, мы прокручиваем вниз, если находимся в состоянии viewAtBottom.

  2. Всякий раз, когда изменяется 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);
   });
}

Для полного примера этого кода в действии см. этот ответ .

...