一种常见的行为是,如果用户没有在其他地方滚动,则将"log“输出小部件滚动到底部。有一些特定于窗口小部件的解决方案,即特定于QTextEdit
或QListView
等,但它们总是需要更改用户代码-而且用户代码已经做了正确的事情,并将数据附加到视图使用的模型中。更改该代码会不适当地将其与视图的细节绑定在一起,因此会有一种糟糕的软件设计味道。
因此,人们可能希望的是一种在不更改用户代码的情况下修改小部件本身行为的方法。此外,也许有一种方法可以在几乎所有从QAbstractScrollArea
派生的类中工作
发布于 2018-08-29 13:49:54
一个可行的解决方案只需要访问视图的滚动条,并且可以很容易地适应于使用滚动条的任何小部件-不仅仅是QAbstractScrollArea
,即使Qt提供的所有垂直滚动小部件确实派生自这个小部件(它们应该是这样的!)。
允许这种低级方法的关键观察结果是,无论何时将内容追加到小部件,垂直滚动条的范围都会发生变化。因此:
每当scrollbar的range
改变时,我们滚动到底部当我们在state.
value
改变的viewAtBottom
中时,我们更新viewAtBottom
以反映scrollbar是否在其范围的末尾(最大值)。这允许用户在内容中自由滚动而不受干扰,但当滚动条放置在那里时,滚动条将“粘在”范围的末尾。
当然,人们希望有一种方法可以为QScrollBar
注入这种行为,但没有任何标志可以启用它-至少在Qt 5.11版本中是这样。
在QAbstractScrollArea
(即QListView
或QListWidget
、QTextEdit
、QTextBrowser
、QPlainTextEdit
等任何项目视图)上调用以下函数时,将使其在添加内容和滚动条范围扩大时保持在底部的行为。
下面的代码在Qt5中工作,并且可以简单地修改为Qt4,将lambdas重新实现为助手类中的插槽。直接获取滚动条的函数也可以被分解出来。
// 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);
});
}
有关此代码实际运行的完整示例,请参阅this answer。
https://stackoverflow.com/questions/52079035
复制相似问题