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

时间:2018-07-15 14:55:47

标签: python qt5 pyqt5

考虑此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_())

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

showcase

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

我想知道为什么我的上述代码片段无法正常工作,并且我想知道随机间隔很小的单次计时器的最佳选择...否则,什么地方合适?确保使用诸如setValue之类的功能后,子窗口小部件将正确绘制。这些东西非常令人困惑,可能会希望showEvent是这样做的适当位置...但是不是:/

1 个答案:

答案 0 :(得分:0)

作为使用单次计时器来确保小部件将正确绘制的替代方法,覆盖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_())