PyQt5-QPainter绘图

QPainter绘图系统

paintEvent事件和绘图区

PyQt5的绘图系统使用户可以在屏幕或打印设备上用相同的API绘图,QPainter是用来进行绘图操作的类,一般的绘图设备包括QWidget、QPixmap、QImage等,这些绘图设备为QPainter提供了一个“画布”。

QWidget类是所有界面组件的基类,QWidget类有一个paintEvent()事件,在此事件里创建一个QPainter对象获取绘图设备的接口,就可以用QPainter对象在绘图设备的“画布”上绘图了。

image

首先创建一个属于本绘图设备的QPainter对象painter,然后使用这个painter在绘图设备的窗口上画图。

image

QWidget的内部绘图区的坐标系统如图8-1所示,坐标系统的单位是像素。左上角坐标为(0, 0),向右是x轴正方向,向下是y轴正方向,绘图区的宽度由QWidget.width()函数得到,高度由QWidget.height()函数得到。这个坐标系统是QWidget的绘图区的局部物理坐标,称为视口(viewport)坐标。相应的还有逻辑坐标,称为窗口(window)坐标,后面会详细介绍。使用QPainter在QWidget上绘图就是在这样的一个矩形区域里绘图。

QPainter绘图的主要属性

用QPainter在绘图设备上绘图,主要是绘制一些基本的图形元素,包括点、直线、圆形、矩形、曲线、文字等,控制这些绘图元素特性的主要是QPainter的以下3个属性。

· pen属性是一个QPen对象,用于控制线条的颜色、宽度、线型等,图8-1中矩形边框的线条的特性就是由pen属性决定的。

· brush属性是一个QBrush对象,用于设置一个区域的填充特性,可以设置填充颜色、填充方式、渐变特性等,还可以采用图片做材质填充。图8-1中的矩形用黄色填充就是由brush属性决定的。

· font属性是一个QFont对象,用于绘制文字时,设置文字的字体样式、大小等属性。

使用这3个属性基本就控制了绘图的基本特点,当然还有一些其他的功能可以结合使用,例如叠加模式、旋转和缩放等功能。

示例程序结构

为演示QPainter绘图的基本功能,使用QPainter对象在一个QWidget窗体的paintEvent()事件函数里直接绘图。界面上无需其他任何组件,所以不创建UI文件,直接创建一个myWidget.py文件,该文件的完整代码如下(此处的import部分还包含了后面的示例代码中要用到的各种类),运行后可得到如图8-1所示的效果。

import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
                         QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)

class QmyWidget(QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
        self.setAutoFillBackground(True)
        self.resize(400,280)
        self.setWindowTitle("QPainter基本绘图")

    def paintEvent(self, event): #在窗口上绘图
        painter=QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setRenderHint(QPainter.TextAntialiasing)
        ##设置画笔
        pen=QPen()
        pen.setWidth(3) #线宽
        pen.setColor(Qt.red) #画线颜色
        pen.setStyle(Qt.SolidLine) #线的类型,如实线、虚线等
        pen.setCapStyle(Qt.FlatCap)# 线端点样式
        pen.setJoinStyle(Qt.BevelJoin)# 线的连接点样式
        painter.setPen(pen)
        ##设置画刷
        brush = QBrush()
        brush.setColor(Qt.yellow)
        # 画刷颜色
        brush.setStyle(Qt.SolidPattern)  # 填充样式
        painter.setBrush(brush)
        ##绘图
        W = self.width()
        # 绘图区宽度
        H = self.height()
        # 绘图区高度
        rect=QRect(W/4,H/4,W/2,H/2)
        painter.drawRect(rect)

if __name__ == "__main__": ##用于当前窗体测试
    app=QApplication(sys.argv) #创建GUI应用程序
    form=QmyWidget() #创建窗体
    form.show()
    sys.exit(app.exec_())

运行之后的效果图:

image

构造函数中设置窗口背景颜色为白色,并设置为自动重绘背景。绘图功能在paintEvent()事件函数里实现,该函数的代码主要包括以下几部分。

· 创建与QWidget对象关联的QPainter对象painter,这样就可以用这个painter在窗体上绘图了。用setRenderHint()设置使用抗锯齿功能,会使图和文字更光滑清晰,但也更消耗运算时间。

· 创建一个QPen类对象pen,设置其线宽、颜色、线型等,然后设置为painter的pen。

· 创建一个QBrush类对象brush,设置其颜色为黄色、填充方式为实体填充,然后设置为painter的brush。

· 获取窗体的宽度和高度,并定义位于中间区域的矩形rect,这个矩形的大小随窗体的大小变化而变化。

· 执行painter.drawRect(rect)就可以绘制矩形rect,矩形框的线条特性由pen属性决定,填充特性由brush属性决定。运行程序就可以得到如图8-1所示的居于窗体中间的填充矩形。

为了不使程序结构过于复杂,可以在paintEvent()函数里直接设置pen和brush的各种属性,而不是设计复杂的界面来修改这些设置。要实现想要的绘图功能和效果,只需在paintEvent()函数里直接修改代码即可。

QPen的主要功能

QPen用于绘图时设置线条,主要包括线宽、颜色、线型等,表8-1是QPen类的主要接口函数。通常每个设置函数都有一个对应的读取函数,例如setColor()用于设置画笔颜色,对应的读取画笔颜色的函数为color(),表8-1仅列出了设置函数,这些函数都没有返回值。

image

线条颜色和宽度的设置无须多说,QPen影响线条特性的另外3个主要属性是线条样式(style)、线条端点样式(capStyle)和线条连接样式(joinStyle)。

image

image

image

image

image

import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
                         QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)

class QmyWidget(QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
        self.setAutoFillBackground(True)
        self.resize(400,280)
        self.setWindowTitle("QPainter基本绘图")

    def paintEvent(self, event):
        painter=QPainter(self)
        painter.setRenderHint(QPainter.Antialiasing)
        painter.setRenderHint(QPainter.TextAntialiasing)
        ##设置画笔
        pen=QPen()
        pen.setWidth(2) #线宽
        pen.setColor(Qt.red) #画线颜色
        painter.setPen(pen)
        ##设置画刷
        texturePixmap=QPixmap("1.jpg")
        brush = QBrush()
        brush.setStyle(Qt.TexturePattern)
        brush.setTexture(texturePixmap)
        painter.setBrush(brush)
        ##绘图
        W = self.width()
        # 绘图区宽度
        H = self.height()
        # 绘图区高度
        rect=QRect(W/5,H/5,3*W/5,3*H/5)
        painter.drawRect(rect)

if __name__ == "__main__": ##用于当前窗体测试
    app=QApplication(sys.argv) #创建GUI应用程序
    form=QmyWidget() #创建窗体
    form.show()
    sys.exit(app.exec_())

image

image

例如,使用QLinearGradient绘制一个渐变填充的矩形区域的paintEvent()事件函数的代码如下:

import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
                         QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)

class QmyWidget(QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
        self.setAutoFillBackground(True)
        self.resize(400,280)
        self.setWindowTitle("QPainter基本绘图")

    def paintEvent(self, event):
        painter=QPainter(self)
        ##设置画笔
        pen=QPen()
        pen.setStyle(Qt.NoPen) #线的类型
        painter.setPen(pen)
        ##绘图
        W = self.width()
        # 绘图区宽度
        H = self.height()
        # 绘图区高度
        rect=QRect(W/4,H/4,W/2,H/2)
        linearGrad=QLinearGradient(rect.left(),rect.top(),rect.right(),rect.top())
        linearGrad.setColorAt(0,Qt.blue)#起点颜色
        linearGrad.setColorAt(0.5, Qt.white)  # 中间点颜色
        linearGrad.setColorAt(1, Qt.blue)  # 终点颜色
        painter.setBrush(linearGrad)
        painter.drawRect(rect)

if __name__ == "__main__": ##用于当前窗体测试
    app=QApplication(sys.argv) #创建GUI应用程序
    form=QmyWidget() #创建窗体
    form.show()
    sys.exit(app.exec_())

image

image

生成如图8-7(b)所示的辐射形渐变填充效果的代码如下:

import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
                         QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)

class QmyWidget(QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
        self.setAutoFillBackground(True)
        self.resize(400,280)
        self.setWindowTitle("QPainter基本绘图")

    def paintEvent(self, event):
        painter=QPainter(self)
        ##设置画笔
        pen=QPen()
        pen.setStyle(Qt.NoPen) #线的类型
        painter.setPen(pen)
        ##绘图
        W = self.width()
        # 绘图区宽度
        H = self.height()
        # 绘图区高度

        radialGrad=QRadialGradient(W/2,H/2,W/3,W/2,H/2)
        radialGrad.setColorAt(0, Qt.white)
        radialGrad.setColorAt(1, Qt.blue)
        painter.setBrush(radialGrad)
        rect=QRect(W/4,H/4,W/2,H/2)
        painter.drawRect(rect)

if __name__ == "__main__": ##用于当前窗体测试
    app=QApplication(sys.argv) #创建GUI应用程序
    form=QmyWidget() #创建窗体
    form.show()
    sys.exit(app.exec_())

image

import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
                         QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)

class QmyWidget(QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
        self.setAutoFillBackground(True)
        self.resize(400,280)
        self.setWindowTitle("QPainter基本绘图")

    def paintEvent(self, event):
        painter=QPainter(self)
        ##设置画笔
        pen=QPen()
        pen.setStyle(Qt.NoPen) #线的类型
        painter.setPen(pen)
        ##绘图
        W = self.width()
        # 绘图区宽度
        H = self.height()
        # 绘图区高度

        radialGrad=QRadialGradient(W/2,H/2,W/2,3*W/4,H/2)
        radialGrad.setColorAt(0, Qt.yellow)
        radialGrad.setColorAt(0.8, Qt.blue)
        painter.setBrush(radialGrad)
        rect=QRect(W/4,H/4,W/2,H/2)
        painter.drawEllipse(rect)

if __name__ == "__main__": ##用于当前窗体测试
    app=QApplication(sys.argv) #创建GUI应用程序
    form=QmyWidget() #创建窗体
    form.show()
    sys.exit(app.exec_())

效果图:

image

image

image

image

image

import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
                         QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)

class QmyWidget(QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
        self.setAutoFillBackground(True)
        self.resize(400,280)
        self.setWindowTitle("QPainter基本绘图")

    def paintEvent(self, event):
        painter=QPainter(self)
        ##设置画笔
        pen=QPen()
        pen.setStyle(Qt.NoPen) #线的类型
        painter.setPen(pen)
        ##绘图
        W = self.width()
        # 绘图区宽度
        H = self.height()
        # 绘图区高度

        radialGrad=QRadialGradient(W/2,H/2,W/8,W/2,H/2)
        radialGrad.setColorAt(0, Qt.yellow)
        radialGrad.setColorAt(1, Qt.blue)
        ##延展模式PadSpread、RepeatSpread、ReflectSpread
        radialGrad.setSpread(QGradient.ReflectSpread)
        painter.setBrush(radialGrad)
        painter.drawRect(self.rect())

if __name__ == "__main__": ##用于当前窗体测试
    app=QApplication(sys.argv) #创建GUI应用程序
    form=QmyWidget() #创建窗体
    form.show()
    sys.exit(app.exec_())

image

import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
                         QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)

class QmyWidget(QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
        self.setAutoFillBackground(True)
        self.resize(400,280)
        self.setWindowTitle("QPainter基本绘图")

    def paintEvent(self, event):
        painter=QPainter(self)
        ##设置画笔
        pen=QPen()
        pen.setStyle(Qt.NoPen) #线的类型
        painter.setPen(pen)
        ##绘图
        W = self.width()
        # 绘图区宽度
        H = self.height()
        # 绘图区高度

        radialGrad=QRadialGradient(W/2,H/2,W/8,W/2,H/2)
        radialGrad.setColorAt(0, Qt.yellow)
        radialGrad.setColorAt(1, Qt.blue)
        ##延展模式PadSpread、RepeatSpread、ReflectSpread
        radialGrad.setSpread(QGradient.PadSpread)
        painter.setBrush(radialGrad)
        painter.drawRect(self.rect())

if __name__ == "__main__": ##用于当前窗体测试
    app=QApplication(sys.argv) #创建GUI应用程序
    form=QmyWidget() #创建窗体
    form.show()
    sys.exit(app.exec_())

image

import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
                         QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)

class QmyWidget(QWidget):
    def __init__(self,parent=None):
        super().__init__(parent)
        self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
        self.setAutoFillBackground(True)
        self.resize(400,280)
        self.setWindowTitle("QPainter基本绘图")

    def paintEvent(self, event):
        painter=QPainter(self)
        ##设置画笔
        pen=QPen()
        pen.setStyle(Qt.NoPen) #线的类型
        painter.setPen(pen)
        ##绘图
        W = self.width()
        # 绘图区宽度
        H = self.height()
        # 绘图区高度

        radialGrad=QRadialGradient(W/2,H/2,W/8,W/2,H/2)
        radialGrad.setColorAt(0, Qt.yellow)
        radialGrad.setColorAt(1, Qt.blue)
        ##延展模式PadSpread、RepeatSpread、ReflectSpread
        radialGrad.setSpread(QGradient.RepeatSpread)
        painter.setBrush(radialGrad)
        painter.drawRect(self.rect())

if __name__ == "__main__": ##用于当前窗体测试
    app=QApplication(sys.argv) #创建GUI应用程序
    form=QmyWidget() #创建窗体
    form.show()
    sys.exit(app.exec_())

image

image

image

posted @ 2022-06-11 10:10  司砚章  阅读(1720)  评论(0编辑  收藏  举报