【问题标题】:Ghost images show up when drawing rect with double buffering tech in PyQt5在 PyQt5 中使用双缓冲技术绘制矩形时出现鬼图像
【发布时间】:2018-12-12 14:53:05
【问题描述】:

这是我的代码:

import sys
from PyQt5.QtCore import Qt, QPoint
from PyQt5.QtGui import QPainter, QPixmap
from PyQt5.QtWidgets import QApplication, QWidget


class Demo(QWidget):
    def __init__(self):
        super(Demo, self).__init__()
        self.resize(600, 600)

        self.pix = QPixmap(600, 600)
        self.pix.fill(Qt.white)

        self.begin_point = QPoint()
        self.end_point = QPoint()

    def paintEvent(self, QPaintEvent):
        painter = QPainter(self)

        x = self.begin_point.x()
        y = self.begin_point.y()
        w = self.end_point.x()-x
        h = self.end_point.y()-y
        painter2 = QPainter(self.pix)       # paint on a QPixmap first
        painter2.drawRect(x, y, w, h)
        painter.drawPixmap(0, 0, self.pix)  # then pain on the widget

    def mousePressEvent(self, QMouseEvent):
        if QMouseEvent.button() == Qt.LeftButton:
            self.begin_point = QMouseEvent.pos()
            self.end_point = self.begin_point

    def mouseMoveEvent(self, QMouseEvent):
        if QMouseEvent.buttons() == Qt.LeftButton:
            self.end_point = QMouseEvent.pos()
            self.update()


if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo = Demo()
    demo.show()
    sys.exit(app.exec_())

我移动得越慢,得到的 rect 鬼影越多(左图越慢)。

首先我希望我的代码能正确理解双缓冲技术。如果不是请指出。

我知道这是由于调用了太多的paintEvent() 引起的。我想知道如何在不删除 mouseMoveEvent() 的情况下使其正确,因为我希望用户在绘制矩形时一直看到它。

【问题讨论】:

    标签: python pyqt pyqt5


    【解决方案1】:

    在这些情况下,有两种类型的数据存储不同类型的信息:永久信息和临时信息。永久的情况下,必须是释放鼠标后的矩形,保存在QPixmap中,临时的必须在拖动鼠标时绘制。

    import sys
    from PyQt5 import QtCore, QtGui, QtWidgets
    
    class Demo(QtWidgets.QWidget):
        def __init__(self):
            super(Demo, self).__init__()
            self.resize(600, 600)
    
            self.pix = QtGui.QPixmap(600, 600)
            self.pix.fill(QtCore.Qt.white)
            self.begin_point, self.end_point = QtCore.QPoint(), QtCore.QPoint()
    
        def paintEvent(self, QPaintEvent):
            painter = QtGui.QPainter(self)
            painter.drawPixmap(QtCore.QPoint(), self.pix)
    
            if not self.begin_point.isNull() and not self.end_point.isNull():
                r = QtCore.QRect(self.begin_point, self.end_point)
                painter.drawRect(r.normalized())
    
        def mousePressEvent(self, event):
            if event.button() & QtCore.Qt.LeftButton:
                self.begin_point = event.pos()
                self.end_point = self.begin_point
                self.update()
    
        def mouseMoveEvent(self, event):
            if event.buttons() & QtCore.Qt.LeftButton:
                self.end_point = event.pos()
                self.update()
    
        def mouseReleaseEvent(self, event):
            if event.button() & QtCore.Qt.LeftButton:
                r = QtCore.QRect(self.begin_point, self.end_point)
                painter = QtGui.QPainter(self.pix)
                painter.drawRect(r.normalized())
                self.begin_point = self.end_point = QtCore.QPoint() 
                self.update()
    
    if __name__ == '__main__':
        app = QtWidgets.QApplication(sys.argv)
        demo = Demo()
        demo.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 谢谢你,但是我不明白painEvent()中的这一行,为什么要先画呢?目的是什么? Painter.drawPixmap(QtCore.QPoint(), self.pix)
    • @la_vie_est_belle inpaintEvent 重绘的时候把前面的东西去掉了,也就是说它没有内存所以如果你要画几个矩形你只能做一个,那我们怎么可能有东西永恒的?您可以使用数据来保存信息,在这种情况下,QPixmap 是正确的。所以我们只需将矩形添加到永久内存(QPixmap)中并在paintEvent + Pixmap = 临时+永久中绘制临时。
    • 感谢您的帮助
    最近更新 更多