QPrintPreviewWidget显示水平滚动条时致应用冻结的问题求助
PySide2 5.15.2.1中QPrintPreviewWidget水平滚动条触发冻结的解决方案
在Windows 11环境下使用PySide2 5.15.2.1时,QPrintPreviewWidget存在一个Bug:当窗口宽度被调整到使控件的滚动区域显示水平滚动条(且文档已有垂直滚动条)时,应用会立即无响应、冻结,直到再次调整窗口让水平滚动条消失才恢复。
触发该Bug的示例代码:
from PySide2.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout from PySide2.QtGui import QTextDocument from PySide2.QtPrintSupport import QPrinter, QPrintPreviewWidget app = QApplication() doc = QTextDocument() doc.setPlainText('\n' * 200) printer = QPrinter() view = QPrintPreviewWidget(printer) view.paintRequested.connect(doc.print_) window = QWidget() layout = QHBoxLayout() layout.addWidget(view) layout.addWidget(QLabel('Just to trigger the horizontal scrollbar')) window.setLayout(layout) window.show() app.exec_()
以下是几种有效的解决方案:
防抖处理打印请求
原代码中直接将paintRequested信号连接到doc.print_,会在滚动条调整过程中频繁触发打印渲染,导致主线程阻塞。添加防抖机制可以避免这种情况:from PySide2.QtWidgets import QApplication, QWidget, QLabel, QHBoxLayout from PySide2.QtGui import QTextDocument from PySide2.QtPrintSupport import QPrinter, QPrintPreviewWidget from PySide2.QtCore import QTimer app = QApplication() doc = QTextDocument() doc.setPlainText('\n' * 200) printer = QPrinter() view = QPrintPreviewWidget(printer) render_timer = QTimer() render_timer.setSingleShot(True) render_timer.setInterval(100) def render_doc(printer): doc.print_(printer) def delayed_render(printer): render_timer.timeout.connect(lambda: render_doc(printer)) render_timer.start() view.paintRequested.connect(delayed_render) window = QWidget() layout = QHBoxLayout() layout.addWidget(view) layout.addWidget(QLabel('Just to trigger the horizontal scrollbar')) window.setLayout(layout) window.show() app.exec_()禁用水平滚动条
直接获取QPrintPreviewWidget内部的滚动区域,强制关闭水平滚动条的显示,从根源上避免触发Bug:# 在创建view后添加以下代码 from PySide2.QtWidgets import QScrollArea from PySide2.QtCore import Qt scroll_area = view.findChild(QScrollArea) if scroll_area: scroll_area.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)升级PySide版本
该Bug大概率是PySide2 5.15.2.1的版本特有问题,后续维护版本(如5.15.7)或PySide6已经修复了这类Windows平台的控件兼容性问题,升级到新版本可以彻底解决。临时规避:设置最小宽度
如提问者所说,通过setMinimumWidth设置控件的最小宽度,确保窗口调整不会触发水平滚动条:view.setMinimumWidth(800) # 根据打印内容的实际宽度调整数值
内容的提问来源于stack exchange,提问作者Carl HR
相关产品推荐
相关产品推荐

