PyQt5图形和特效之双缓存绘图(三)

版权声明:如有使用转载,请附加出处 https://blog.csdn.net/jia666666/article/details/81868111

实例:绘制矩形,出现重影

在画板上绘制矩形

# -*- coding: utf-8 -*-


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


class Winform(QWidget):
    def __init__(self, parent=None):
        super(Winform, self).__init__(parent)
        self.setWindowTitle("绘制矩形例子")

        self.pix = QPixmap()
        self.lastPoint = QPoint()
        self.endPoint = QPoint()
        self.initUi()

    def initUi(self):
        # 窗口大小设置为600*500
        self.resize(600, 500)

        # 画布大小为400*400,背景为白色
        self.pix = QPixmap(400, 400)
        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

        pp=QPainter(self.pix)
        #指定位置绘制矩形
        pp.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()

    def mouseReleaseEvent(self, event):
        # 鼠标左键释放
        if event.button() == Qt.LeftButton:
            self.endPoint = event.pos()
            # 进行重新绘制
            self.update()


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

运行结果如下
这里写图片描述

思路分析

在这个例子中,首先将图形绘制在画布上,然后将画布绘制到窗口中
重构painEvent()函数,在函数中添加初始化代码,就是通过lastPoint和endPoint两个点来确定所要绘制矩形的起点,宽度与高度
运行程序,使用鼠标拖出一个矩形,发现出现了很多重影,为u什么会有重影呢?
可以尝试分别快速和慢速的拖动鼠标来绘制矩形,结果发现,拖动速度越快重影越少,其实,鼠标拖动的过程中,屏幕已经刷新很多次了,也可以理解为paintEvent()函数执行了多次,每执行一次就会绘制一个矩形,知道了原因,就可以想办法解决问题了

实例二:双缓冲绘制矩形

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

class Winform(QWidget):
    def __init__(self,parent=None):
        super(Winform, self).__init__(parent)
        self.setWindowTitle('双缓存绘图例子')
        #主画布
        self.pix=QPixmap()
        self.lastPoint=QPoint()
        self.endPoint=QPoint()
        #辅助画布
        self.tempix=QPixmap()
        #标志:当前是否在画图
        self.isDrawing=False
        self.initUI()
    def initUI(self):
        #设置窗口大小:600*500
        self.resize(600,500)
        #设置画布大小:400*400
        self.pix=QPixmap(400,400)
        #画布背景颜色填充:白色
        self.pix.fill(Qt.white)

    #重构paintEvent函数
    def paintEvent(self, QPaintEvent):

        painter=QPainter(self)

        #矩形的属性
        x=self.lastPoint.x()
        y=self.lastPoint.y()
        w=self.endPoint.x()-x
        h=self.endPoint.y()-y

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

    def mousePressEvent(self, QMouseEvent):
        #按下鼠标左键
        if QMouseEvent.button()==Qt.LeftButton:
            #获得鼠标的属性值,x,y坐标值
            self.lastPoint=QMouseEvent.pos()
           # print(self.lastPoint)
            self.endPoint=self.lastPoint
            self.isDrawing=True

    def mouseReleaseEvent(self, QMouseEvent):
        #释放鼠标左键
        if QMouseEvent.button()==Qt.LeftButton:
            self.endPoint=QMouseEvent.pos()
            #进行重新绘制
            self.update()
            self.isDrawing=False
if __name__ == '__main__':
    app=QApplication(sys.argv)
    form=Winform()
    form.show()
    sys.exit(app.exec_())

运行程序,效果如下
这里写图片描述

代码分析

在这个例子中,按下鼠标左键时标志正在绘图,当释放左键时,则取消正在绘图的标志,运行程序,绘图正常,没有重影
在这个例子中,需要添加一个辅助画布,如果正在绘图,也就是还没有释放鼠标左键时,就在辅助画布上进行,只有释放鼠标左键,才在主画布上绘图

第一组代码:添加两个变量

         #辅助画布
        self.tempix=QPixmap()
        #标志:当前是否在画图
        self.isDrawing=False

第二组代码:重构painEvent()函数,如果正在绘图,就在辅助画布上进行,将以前pix中的内容复制到temPix中,保证以前的内容不消失

 if self.isDrawing:
            #将之前pix中的内容复制到tempix中,保证以前的内容不消失
            self.tempix=self.pix
            pp=QPainter(self.tempix)
            #绘制矩形在画布
            pp.drawRect(x,y,w,h)
            #重新绘制画布到窗口
            painter.drawPixmap(0,0,self.tempix)
        else:
            pp=QPainter(self.pix)
            pp.drawRect(x,y,w,h)
            painter.drawPixmap(0,0,self.pix)

第三组代码:重构mousePressEvent()函数,更改鼠标左键按下时处理函数的内容

    def mousePressEvent(self, QMouseEvent):
        #按下鼠标左键
        if QMouseEvent.button()==Qt.LeftButton:
            #获得鼠标的属性值,x,y坐标值
            self.lastPoint=QMouseEvent.pos()
           # print(self.lastPoint)
            self.endPoint=self.lastPoint
            self.isDrawing=True

第四组代码:重构mouseReleaseEvent()函数,更改鼠标左键释放时处理函数的内容

 def mouseReleaseEvent(self, QMouseEvent):
        #释放鼠标左键
        if QMouseEvent.button()==Qt.LeftButton:
            self.endPoint=QMouseEvent.pos()
            #进行重新绘制
            self.update()
            self.isDrawing=False

双缓存技术总结

在这个例子中,要实现使用鼠标在界面上绘制一个任意大小的矩形而不出现重影,需要两个画布,他们都是QPixmap实例,其中tenpPix作为临时缓冲区,当拖动鼠标绘制矩形时,将内容先绘制到tempPix上,然后再将tempix绘制到界面上,pix作为缓冲区,用来保存已经完成的绘制,当释放鼠标左键完成矩形绘制后,则将tempix的内容复制到pix上,为了在绘制时不出现重影,而且保证之前绘制的内容不消失,那么每一次绘制都是在原来的图像上进行的,所以需要在绘制tempix之前,先将pix的内容复制到tempix上,因为这里有两个QPixmap对象,也可以说有两个缓存区,所以称之为双缓冲绘图

相关源码及素材
https://download.csdn.net/download/jia666666/10616087

猜你喜欢

转载自blog.csdn.net/jia666666/article/details/81868111