PyQt5之绘图

在PyQt中常用的图像类有4个,即QPixmap、QImage、QPicture和QBitmap。

  • QPixmap是专门为绘图而设计的,在绘制图片时需要使用QPixmap;
  • QImage提供了一个与硬件无关的图像表示函数,可以用于图片的像素级访问;
  • QPicture是一个绘图设备类,它继承自QPainter类,可以使用QPainter的begin()函数在QPicture上绘图,使用end()函数结束绘图,使用QPicture的save()函数将QPainter所使用过的绘图指令保存到文件中;
  • QBitmap是一个继承自QPixmap的简单类,它提供了1bit深度的二值图像的类,QBitmap提供的单色图像可以用来制作游标(QCursor)或者笔刷(QBrush)。

一、简单绘图

import sys
from PyQt5 import QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class Demo(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('简单绘图')
        self.pix = QPixmap()
        self.lastPoint = QPoint()
        self.endPoint = QPoint()
        self.initUI()

    def initUI(self):
        self.resize(600, 500)
        self.pix = QPixmap(600, 500)  # 设置画布大小
        self.pix.fill(Qt.white)  # 设置画布背景颜色为白色

    # 绘图
    def paintEvent(self, event):
        p = QPainter(self.pix)
        p.drawLine(self.lastPoint, self.endPoint)  # 根据鼠标指针前后两个位置绘制直线
        self.lastPoint = self.endPoint  # 让前一个坐标值等于后一个坐标值,就能画出连续的线
        painter = QPainter(self)
        painter.drawPixmap(0, 0, self.pix)

    #当鼠标左键按下时触发该函数
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.lastPoint = event.pos()
            self.endPoint = self.lastPoint

    #当鼠标左键移动时触发该函数
    def mouseMoveEvent(self, event):
        if event.buttons() and Qt.LeftButton:
            self.endPoint = event.pos()
            self.update()#调用paintEvent函数,重新绘制

    #当鼠标左键释放时触发该函数
    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.endPoint = event.pos()
            self.update()  # 调用paintEvent函数,重新绘制

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

运行效果如下:

pyqt5opencv图像处理界面设计_双缓冲


注:在重构mouseMoveEvent函数时,buttons()函数可以获取鼠标指针移动过程中按下的所有按键,然后用Qt.LeftButton来判断是否按下了左键,必须使用该函数来判断按下鼠标的按键。

二、双缓冲绘图

  1. 绘制矩形,出现重影:
import sys
from PyQt5 import QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class Demo(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('绘制矩形,出现重影')
        self.pix = QPixmap()
        self.lastPoint = QPoint()
        self.endPoint = QPoint()
        self.initUI()

    def initUI(self):
        self.resize(600, 500)
        self.pix = QPixmap(600, 500)  # 设置画布大小
        self.pix.fill(Qt.white)  # 设置画布背景颜色为白色

    # 绘图
    def paintEvent(self, event):
        p = QPainter(self.pix)
        painter = QPainter(self)
        x = self.lastPoint.x()
        y = self.lastPoint.y()
        w = self.endPoint.x()-x
        h = self.endPoint.y()-y
        p.drawRect(x,y,w,h)
        painter.drawPixmap(0, 0, self.pix)

    #当鼠标左键按下时触发该函数
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.lastPoint = event.pos()
            self.endPoint = self.lastPoint

    #当鼠标左键移动时触发该函数
    def mouseMoveEvent(self, event):
        if event.buttons() and Qt.LeftButton:
            self.endPoint = event.pos()
            self.update()#调用paintEvent函数,重新绘制

    #当鼠标左键释放时触发该函数
    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.endPoint = event.pos()
            self.update()  # 调用paintEvent函数,重新绘制

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

运行效果如下:

pyqt5opencv图像处理界面设计_Qt_02


注:其实,在拖动鼠标的过程中屏幕已经刷新了很多次,即paintEvent函数执行了很多次,每执行一次就会绘制一个矩形,拖动速度越快,重影越少。

  1. 使用双缓冲技术绘制矩形,避免出现重影:
import sys
from PyQt5 import QtCore
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

class Demo(QWidget):
    def __init__(self):
        super().__init__()
        self.setWindowTitle('使用双缓冲技术绘制矩形,避免出现重影')
        self.pix = QPixmap()
        self.lastPoint = QPoint()
        self.endPoint = QPoint()
        self.temPix = QPixmap()#辅助画布
        self.isDrawing = False  #标志是否正在绘图
        self.initUI()

    def initUI(self):
        self.resize(600, 500)
        self.pix = QPixmap(600, 500)  # 设置画布大小
        self.pix.fill(Qt.white)  # 设置画布背景颜色为白色

    # 绘图
    def paintEvent(self, event):
        painter = QPainter(self)
        x = self.lastPoint.x()
        y = self.lastPoint.y()
        w = self.endPoint.x()-x
        h = self.endPoint.y()-y

        #如果正在绘图,就在辅助画布上绘制
        if self.isDrawing:
            self.temPix = self.pix  #将以前pix中的内容复制到辅助画布中,保证以前的内容不消失
            p = QPainter(self.temPix)
            p.drawRect(x,y,w,h)
            painter.drawPixmap(0, 0, self.pix)
        else:
            p = QPainter(self.pix)
            p.drawRect(x, y, w, h)
            painter.drawPixmap(0, 0, self.pix)

    #当鼠标左键按下时触发该函数
    def mousePressEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.lastPoint = event.pos()
            self.endPoint = self.lastPoint
            self.isDrawing = True

    #当鼠标左键释放时触发该函数
    def mouseReleaseEvent(self, event):
        if event.button() == Qt.LeftButton:
            self.endPoint = event.pos()
            self.update()  # 调用paintEvent函数,重新绘制
            self.isDrawing = False

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

运行效果如下:

pyqt5opencv图像处理界面设计_pyqt_03

双缓冲技术总结:
在这个例子中,要实现使用鼠标在界面上绘制一个任意大小的矩形而不出现重影,需要两个画布,其中一个作为临时缓冲区。为了在绘制时不出现重影,而且保证以前绘制的内容不消失,那么每一次绘制都是在原来的图形上进行的,所以需要绘制在辅助画布之前,先将pix的内容复制到辅助画布上。