如何将 QPlainTextEdit verticalScrollBar 设置为最大值?

Posted

技术标签:

【中文标题】如何将 QPlainTextEdit verticalScrollBar 设置为最大值?【英文标题】:How to set QPlainTextEdit verticalScrollBar to maximum? 【发布时间】:2018-07-15 14:55:46 【问题描述】:

考虑一下这个 mcve:

import sys
from datetime import datetime

from PyQt5.Qt import *  # noqa


class Foo(QPlainTextEdit):

    def __init__(self, parent=None):
        super().__init__(parent)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_P:
            self.appendPlainText(f"New line")
        super().keyPressEvent(event)


class FooWindow(QMainWindow):

    def __init__(self, parent=None):
        super().__init__(parent)

        m = self.menuBar().addMenu("&Debug")
        action = QAction("Baz", self)
        action.triggered.connect(self.bar)
        action.setShortcut("Ctrl+N")
        m.addAction(action)

        self.obj = Foo()
        self.obj.setLineWrapMode(QPlainTextEdit.NoWrap)

        for i in range(20):
            self.obj.appendPlainText(f"Line_i" * 10)

        self.obj_dock = QDockWidget('Console', self)
        self.obj_dock.setWidget(self.obj)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.obj_dock)

    def bar(self):
        self.obj.appendPlainText(f"New line from menu action")

    def showEvent(self, event):
        bar = self.obj.verticalScrollBar()
        bar.setValue(bar.maximum())
        print(f"2) showEvent now()")


def now():
    return datetime.utcnow().strftime('%H:%M:%S.%f')[:-3]


if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = FooWindow()
    print(f"1) before show now()")
    ex.show()
    print(f"3) after show now()")

    # ex.obj.ensureCursorVisible()
    bar = ex.obj.horizontalScrollBar()
    bar.setValue(bar.minimum())
    bar = ex.obj.verticalScrollBar()
    bar.setValue(bar.maximum())

    print(f"4) manual bar.setValue now()")

    # timer = QTimer()
    # timer.setInterval(10)
    # timer.setSingleShot(True)
    # def set_scrollbar_at_maximum():
    #     bar = ex.obj.verticalScrollBar()
    #     bar.setValue(ex.obj.verticalScrollBar().maximum())
    #     print(f"5) bar.setValue from timer now()")
    # timer.timeout.connect(set_scrollbar_at_maximum)
    # timer.start()

    sys.exit(app.exec_())

我想查看最后添加的行,而不必手动向下滚动垂直条。在ex.show()def showEvent(self, event): 之后调用bar.setValue(ex.obj.verticalScrollBar().maximum()) 不起作用,即:

问题是,除非我手动向下滚动垂直条或使用单次计时器设置值,否则最后添加的行将不可见。

我想知道为什么我上面的 sn-p 不能正常工作,我想知道这些单次计时器的最佳替代品,这些单次计时器具有随机的小间隔......否则,什么是合适的地方这将保证在使用 setValue 等函数后正确绘制子小部件。这东西很令人困惑,人们会期望 showEvent 是一个合适的地方这样做......但它不是:/

【问题讨论】:

【参考方案1】:

作为使用单次计时器的替代方法来保证小部件将被正确绘制,似乎覆盖QMainWindow::event 是一个不错的选择,这里有一个可能的问题解决方案:

import sys
from datetime import datetime

from PyQt5.Qt import *  # noqa


class Foo(QPlainTextEdit):

    def __init__(self, parent=None):
        super().__init__(parent)

    def keyPressEvent(self, event):
        if event.key() == Qt.Key_P:
            self.appendPlainText(f"New line")
        super().keyPressEvent(event)


class FooWindow(QMainWindow):

    def __init__(self, parent=None):
        super().__init__(parent)

        m = self.menuBar().addMenu("&Debug")
        action = QAction("Baz", self)
        action.triggered.connect(self.bar)
        action.setShortcut("Ctrl+N")
        m.addAction(action)

        self.obj = Foo()
        self.obj.setLineWrapMode(QPlainTextEdit.NoWrap)

        for i in range(20):
            self.obj.appendPlainText(f"Line_i" * 10)

        self.obj_dock = QDockWidget('Console', self)
        self.obj_dock.setWidget(self.obj)
        self.addDockWidget(Qt.BottomDockWidgetArea, self.obj_dock)
        self.window_shown = False

    def bar(self):
        self.obj.appendPlainText(f"New line from menu action")

    def update_widgets(self):
        if self.window_shown:
            return

        bar = ex.obj.horizontalScrollBar()
        bar.setValue(bar.minimum())
        bar = self.obj.verticalScrollBar()
        bar.setValue(bar.maximum())
        self.window_shown = True

    def event(self, ev):
        ret_value = super().event(ev)

        if ev.type() == QEvent.Paint:
            self.update_widgets()

        return ret_value


if __name__ == "__main__":
    app = QApplication(sys.argv)
    ex = FooWindow()
    ex.show()
    sys.exit(app.exec_())

【讨论】:

以上是关于如何将 QPlainTextEdit verticalScrollBar 设置为最大值?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 QPlainTextEdit verticalScrollBar 设置为最大值?

如何在 QPlainTextEdit 小部件中突出显示整行文本?

如何从 QPlainTextEdit 正确获取 Unicode 文本输入? [复制]

如何知道 QPlainTextEdit 继承类中是不是显示水平滚动条?

如何使 QPlainTextEdit 看起来像一个 .txt 文件?

如何使用 QPlainTextEdit 编辑器结束编辑会话?