考虑此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):
不起作用,即:
事实是,除非我手动向下滚动垂直栏或使用单次计时器设置值,否则最后添加的行将不可见。
我想知道为什么我的上述代码片段无法正常工作,并且我想知道随机间隔很小的单次计时器的最佳选择...否则,什么地方合适?确保使用诸如setValue之类的功能后,子窗口小部件将正确绘制。这些东西非常令人困惑,可能会希望showEvent是这样做的适当位置...但是不是:/
答案 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_())