python - 不应再在小部件的paintEvent 上调用paintEngine
问题描述
我正在尝试在单击时重新绘制一个列表小部件项目,但我在使用QPainter
. 代码“有效”,但在每次 GUI 重绘时,它都会显着滞后并输出下面的警告,并且不知道是什么原因造成的,因为它都是在内部完成的paintEvent
(也许我没有QPainter
正确交换对象?)
每次重绘时,GUI 都会冻结并输出:
QWidget::paintEngine: Should no longer be called
QPainter::begin: Paint device returned engine == 0, type: 1
QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::setRenderHint: Painter must be active to set rendering hints
QPainter::fillPath: Painter not active
QPainter::setPen: Painter not active
QPainter::drawPath: Painter not active
QPainter::setClipPath: Painter not active
QPainter::end: Painter not active, aborted
import sys
from PyQt5 import QtCore, QtWidgets
from PyQt5 import QtGui
from PyQt5.QtGui import QColor, QFont, QImage, QPainter, QPainterPath, QPixmap
class QCustomQWidget(QtWidgets.QWidget):
def __init__(self, parent=None, ref_parent=None):
super(QCustomQWidget, self).__init__(parent)
self.textQVBoxLayout = QtWidgets.QVBoxLayout()
self.ref_parent = ref_parent
self.shadow_effects = {}
self.shadow_effects_counter = 0
self.textUpQLabel = QtWidgets.QLabel()
font = QFont()
font.setPointSize(12)
self.textUpQLabel.setFont(font)
self.textQVBoxLayout.addWidget(self.textUpQLabel)
self.allQGrid = QtWidgets.QGridLayout()
self.thumbnailQLabel = QtWidgets.QLabel()
self.allQGrid.addWidget(self.thumbnailQLabel, 0, 0, 2, 1, QtCore.Qt.AlignLeft)
self.allQGrid.addLayout(self.textQVBoxLayout, 0, 1, 2, 1, QtCore.Qt.AlignLeft)
self.setLayout(self.allQGrid)
def paintEvent(self, event):
target = self
painter = QPainter(target)
painter = self.set_painter_color(painter, target, QColor(224, 224, 224))
painter.end()
if self.ref_parent.item_widget_to_repaint is not None:
# change color for the clicked list item
target = self.ref_parent.item_widget_to_repaint
painter = QPainter(target)
painter = self.set_painter_color(painter, target, QColor(129, 173, 244))
painter.end()
def set_painter_color(self, painter, target, color: QColor):
painter.setRenderHint(QPainter.Antialiasing, True)
painter.setRenderHint(QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QPainter.SmoothPixmapTransform, True)
rect = QtCore.QRectF(target.rect())
painter_path = QPainterPath()
painter_path.addRoundedRect(rect, 20, 20)
painter.fillPath(painter_path, QtGui.QBrush(color))
painter.setPen(QtCore.Qt.NoPen) # remove border when clipping
painter.drawPath(painter_path)
painter.setClipPath(painter_path)
return painter
def setTextUp(self, text):
self.textUpQLabel.setText(text)
self.textUpQLabel.setSizePolicy(
QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.MinimumExpanding
)
)
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setLayout(QtWidgets.QVBoxLayout())
self.checkbox_dict = dict()
self.button_dict = dict()
self.listWidget = QtWidgets.QListWidget()
self.layout().addWidget(self.listWidget)
self.item_widget_to_repaint = None
text = ["ITEM 1", "ITEM 2", "ITEM 3"]
for i in text:
myQCustomQWidget = QCustomQWidget(ref_parent=self)
myQCustomQWidget.setTextUp(i)
myQListWidgetItem = QtWidgets.QListWidgetItem(self.listWidget)
myQListWidgetItem.setSizeHint(myQCustomQWidget.sizeHint())
self.listWidget.addItem(myQListWidgetItem)
self.listWidget.setItemWidget(myQListWidgetItem, myQCustomQWidget)
self.listWidget.itemClicked.connect(lambda item: self.on_list_item_click(item))
self.resize(800, 300)
self.show()
def on_list_item_click(self, item: QtWidgets.QListWidgetItem):
widget = item.listWidget().itemWidget(item)
# set target for paintevent in QCustomQWidget
self.item_widget_to_repaint = widget
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
sys.exit(app.exec())
解决方案
小部件的绘制应该只在它自己的paintEvent中完成,而不是像你正在做的那样在另一个小部件中完成,这就是Qt用这些错误消息发出的警告。
在这种情况下,逻辑是创建一个包含颜色并调用以重新绘制小部件的属性。
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
class QCustomQWidget(QtWidgets.QWidget):
def __init__(self, parent=None, ref_parent=None):
super(QCustomQWidget, self).__init__(parent)
self.textQVBoxLayout = QtWidgets.QVBoxLayout()
self.ref_parent = ref_parent
self.shadow_effects = {}
self.shadow_effects_counter = 0
self.textUpQLabel = QtWidgets.QLabel()
font = QtGui.QFont()
font.setPointSize(12)
self.textUpQLabel.setFont(font)
self.textQVBoxLayout.addWidget(self.textUpQLabel)
self.allQGrid = QtWidgets.QGridLayout(self)
self.thumbnailQLabel = QtWidgets.QLabel()
self.allQGrid.addWidget(self.thumbnailQLabel, 0, 0, 2, 1, QtCore.Qt.AlignLeft)
self.allQGrid.addLayout(self.textQVBoxLayout, 0, 1, 2, 1, QtCore.Qt.AlignLeft)
self._color = QtGui.QColor(224, 224, 224)
@property
def color(self):
return self._color
@color.setter
def color(self, color):
if self.color == color:
return
self._color = color
self.update()
def paintEvent(self, event):
painter = QtGui.QPainter(self)
painter.setRenderHint(QtGui.QPainter.Antialiasing, True)
painter.setRenderHint(QtGui.QPainter.HighQualityAntialiasing, True)
painter.setRenderHint(QtGui.QPainter.SmoothPixmapTransform, True)
rect = QtCore.QRectF(self.rect())
painter_path = QtGui.QPainterPath()
painter_path.addRoundedRect(rect, 20, 20)
painter.fillPath(painter_path, QtGui.QBrush(self.color))
painter.setPen(QtCore.Qt.NoPen)
painter.drawPath(painter_path)
painter.setClipPath(painter_path)
def setTextUp(self, text):
self.textUpQLabel.setText(text)
self.textUpQLabel.setSizePolicy(
QtWidgets.QSizePolicy(
QtWidgets.QSizePolicy.MinimumExpanding,
QtWidgets.QSizePolicy.MinimumExpanding,
)
)
class MainWindow(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setLayout(QtWidgets.QVBoxLayout())
self.checkbox_dict = dict()
self.button_dict = dict()
self.listWidget = QtWidgets.QListWidget()
self.layout().addWidget(self.listWidget)
self.item_widget_to_repaint = None
text = ["ITEM 1", "ITEM 2", "ITEM 3"]
for i in text:
myQCustomQWidget = QCustomQWidget(ref_parent=self)
myQCustomQWidget.setTextUp(i)
myQListWidgetItem = QtWidgets.QListWidgetItem(self.listWidget)
myQListWidgetItem.setSizeHint(myQCustomQWidget.sizeHint())
self.listWidget.addItem(myQListWidgetItem)
self.listWidget.setItemWidget(myQListWidgetItem, myQCustomQWidget)
self.listWidget.itemClicked.connect(self.on_list_item_click)
self.resize(800, 300)
def on_list_item_click(self, item: QtWidgets.QListWidgetItem):
widget = item.listWidget().itemWidget(item)
widget.color = QtGui.QColor(129, 173, 244)
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = MainWindow()
w.show()
sys.exit(app.exec())
推荐阅读
- python - Python - 根据变量触发特定函数
- relational-database - 这张表是 1NF 还是 2NF?
- babylonjs - 在网格点击时,ArcRotateCamera 专注于
- wpf - 在 ControlTemplate.Triggers 中查找 AncestorType 的问题
- java - 显示错误的输出,我无法弄清楚我的错误
- python - scipy.stats.chi2 返回 Nan 概率
- r - 如何计算每小时的入住率?
- javascript - 如何在 Markdown 文件中嵌入视频、图片库、表单?
- kotlin - 具有通用输入的高阶函数的重载分辨率模糊性
- python - 如何将身份验证功能放入烧瓶中的@app.before_request