34. QPainter绘图技术

一、QPainter绘图

  绘图是指在绘图设备(窗口、控件、图像、打印机等)上将用户构思出的图形绘制出来,图形包括点、线、矩形、多边形、椭圆、文字及保存到磁盘上的图像等。可以对绘制的图形进行处理,如给封闭的图形填充颜色。

  绘图设备是从 QPaintDevice 继承的类,包括继承自 QWidget 的窗口、各种控件、QPixmapQImage。如果绘图设备是窗口或控件,则 QPainter 绘图一般放到 paintEvent() 事件或者被 paintEvent() 事件调用的函数中。

  我们可以在终端中使用 pip 安装 PySide6 模块。默认是从国外的主站上下载,因此,我们可能会遇到网络不好的情况导致下载失败。我们可以在 pip 指令后通过 -i 指定国内镜像源下载

pip install pyside6 -i https://mirrors.aliyun.com/pypi/simple

  国内常用的 pip 下载源列表:

  用 QPainter 类创建绘图实例的方法如下:

QPainter()
QPainter(device=QPaintDevice)

  其中 QPaintDevice 是指继承自 QPaintDevice 的绘图设备。如果使用不带设备的 QPainter() 方法创建实例对象,,则在开始绘图前需要用 painter.begin(device:QPaintDevice) 方法 指定绘图设备,此时 painter.isActive() 的返回值是 True,绘图完成后,需要用 painter.end() 方法 声明完成绘图,之后可以用 begin() 方法 重新指定绘图设备begin()end() 方法都返回 bool 值。

  QPainter 类常用对状态进行设置的方法如下:

# 设置背景色,背景色只对不透明的文字、虚线或位图起作用
setBackground(bg:Union[QBursh, Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage, QPixmap]) -> None  
setBackgroundMode(mode:Qt.BGMode) -> None                                       # 设置透明或不透明背景模式

setFont(f:Union[QFont, str, Sequence[str]]) -> None                             # 设置字体
setLayoutDirection(direction:Qt.LayoutDirection) -> None                        # 设置布局方向
setOpacity(opacity:float) -> None                                               # 设置不透明度

# 设置画刷
setBrush(brush:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage, QPixmap]) -> None   
setBrush(style:Qt.BrushStyle) -> None                                           # 设置画刷
setBrushOrigin(origin:Union[QPointF, QPoint, QPainterPath.Element]) -> None     # 设置画刷的起点
setBrushOrigin(x:int, y:int) -> None                                            # 设置画刷的起点

setPen(pen:Union[QPen, Qt.PenStyle, QColor]) -> None                            # 设置钢笔
setPen(color:Union[QColor, Qt.GlobalColor, str]) -> None                        # 设置钢笔

setClipPath(path:QPainterPath, op:Qt.ClipOperation=Qt.ReplaceClip) -> None      # 设置剪切路径
setClipRect(rect:QRect, op:Qt.ClipOperation=Qt.ReplaceClip) -> None             # 设置剪切矩形区域
setClipRect(arg_1:Union[QRectF, QRect], op:Qt.ClipOperation=Qt.ReplaceClip) -> None             # 设置剪切矩形区域
setClipRect(x:int, y:int, w:int, h:int, op:Qt.ClipOperation=Qt.ReplaceClip) -> None             # 设置剪切矩形区域
setClipRegion(arg__1:Union[QRegion, QBitmap, QPolygon, QRect], op=Qt.ReplaceClip) -> None       # 设置剪切区域
setClipping(enable:bool) -> None                                                                # 设置是否启动剪切

setCompositionMode(mode:QPainter.CompositionMode) -> None                       # 设置图形的合成模式

setRenderHint(hint:QPainter.RenderHint, on:bool=true) -> None                   # 设置渲染模式
setRenderHints(hints:QPainter.RenderHints, on:bool=true) -> None                # 设置多个渲染模式

setTransform(transform:QTransform, combine:bool=false) -> None                  # 设置全局变化矩阵
setWorldTransform(matrix:QTransform, combine:bool=false) -> None                # 设置全局变化矩阵
setViewTransformEnabled(enable:bool) -> None                                    # 设置是否启动视图变换
setViewport(viewport:QRect) -> None                                             # 设置视口
setViewport(x:int, y:int, w:int, h:int) -> None                                 # 设置视口
setWindow(window:QRect) -> None                                                 # 设置逻辑窗口
setWindow(x:int, y:int, w:int, h:int) -> None                                   # 设置逻辑窗口
setWorldMatrixEnabled(enabled:bool) -> None                                     # 设置是否启动全局矩阵变换

save() -> None                                                                  # 保存状态到堆栈中
restore() -> None                                                               # 从堆栈中恢复状态

二、设置钢笔

  钢笔 QPen 用于 绘制线条,线条有样式(实线、虚线、点虚线)、颜色、宽度等属性,用 QPaintersetPen(QPen) 方法为 QPainter 设置钢笔

QPen()

QPen(style:Qt.PenStyle)

QPen(color:Union[QColor, Qt.GlobalColor, str, int])

QPen(pen:Union[QPen, Qt.PenStyle, QColor])

QPen(brush:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage, QPixmap], width:float, style:Qt.PenStyle=Qt.PenStyle.SolidLine, c:Qt.PenCapstyle=Qt.PenCapstyle.SquareCap, j:Qt.PenJoinstyle=Qt.PenJoinstyle.BevelJoin)

  参数 style 用于 设置钢笔的样式,它是 Qt.PenStyle 的枚举值,可以取值如下:

Qt.PenStyle.NoPen                                                               # 不绘制线条
Qt.PenStyle.SolidLine                                                           # 实线
Qt.PenStyle.DashLine                                                            # 虚线
Qt.PenStyle.DotLine                                                             # 点线
Qt.PenStyle.DashDotLine                                                         # 点画线
Qt.PenStyle.DashDotDotLine                                                      # 双点划线
Qt.PenStyle.CustomDashLine                                                      # 自定义线

钢笔的样式

  参数 c 用于 设置线条端点样式,它是 Qt.PenCapStyle 的枚举值,可以取值如下:

Qt.PenCapStyle.FlatCap                                                          # 不包含端点
Qt.PenCapStyle.SquareCap                                                        # 包含端点
Qt.PenCapStyle.RoundCap                                                         # 包含端点,并延长半个宽度

钢笔的端点

  参数 j 用于 设置线条连接点处的样式,它是 Qt.PenJoinStyle 的枚举值,可以取值如下:

Qt.PenJoinStyle.MiterJoin
Qt.PenJoinStyle.BevelJoin
Qt.PenJoinStyle.RoundJoin
Qt.PenJoinStyle.SvgMiterJoin

线条连接样式

钢笔默认的 颜色黑色宽度1 像素样式实线端点样式Qt.SquareCap连接处Qt.BevelJoin

  QPen 类的常用方法如下:

setStyle(style:Qt.PenStyle) -> None                                             # 设置线条样式
style() - Qt.PenStyle                                                           # 获取线条样式

setWidth(width:int) -> None                                                     # 设置线条宽度
setWidth(width:float) -> None                                                   # 设置线条宽度

isSolid() -> bool                                                               # 获取线条样式是否是实现填充

setBrush(brush:Union[QBrush, Qt.BrushStyle, QColor, Qt.GlobalColor, QGradient, QImage, QPixmap]) -> None    # 设置画刷
brush() -> QBrush                                                               # 获取画刷

setCapStyle(style:Qt.PenCapStyle) -> None                                       # 设置线端部的样式
capStyle() -> Qt.PenCapStyle                                                    # 获取线端部的样式

setColor(color:Union[QColor, Qt.GlobalColor, str, int]) -> None                 # 设置颜色
color() -> QColor                                                               # 获取颜色

setCosmetic(cosmetic:bool) -> None                                              # 设置是否进行装饰
isCosmetic() -> bool                                                            # 获取是否进行装饰

setDashOffset(doffset:float) -> None                                            # 设置虚线开始绘制的点与线起始点的距离
setDashPattern(pattern:Sequence[float]) -> None                                 # 设置用户自定义虚线样式
setJoinStyle(style:Qt.PenJoinStyle) -> None                                     # 设置两相交线连接点出的样式
setMiterLimit(length:float) -> None                                             # 设置斜接延长线的长度

  线条的宽度setWidth(width:int)setWidthF(width:float) 方法设置,如果宽度始终为 0,表示是 装饰线条装饰线条 也可用 setCosmetic(bool) 方法设置。装饰线条 是指具有恒定宽度的边,可确保线条在不同缩放比例下具有相同的宽度。线条的样式setStyle(Qt.PenStyle) 方法设置。钢笔的端点样式setCapStyle(Qt.PenCapStyle) 方法设置。两个线条连接点处的样式setJoinStyle(Qt.PenJoinStyle) 方法设置。

  如果线条连接样式是 Qt.PenJoinStyle.MiterJoin 时,用 setMiterLimit(widht:float) 方法 设置延长线的长度,其中参数 width 是 线条宽度的倍数,默认是2.0,其延长线的含义如下所示。

延长线

  用 setDashPattern(Sequence[float]) 方法可以 自定义虚线样式,其中参数的 奇数项表示实线的长度偶数项表示空白处的长度,长度以线宽为单位,表示为线宽的倍数。

  用 setDashOffset(distance:float) 方法可以 设置虚线开始绘制的点与线起始点之间的距离,如果这个距离是动态的,则会形成动画效果。

  新建一个 template.py 文件。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import QPointF, Qt
from PySide6.QtGui import QPainter, QPaintEvent, QPen

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象  
        pen = QPen()                                                            # 2.创建画笔对象

        pen.setColor(Qt.GlobalColor.blue)                                       # 3.设置线条颜色
        pen.setWidth(10)                                                        # 4.设置线条宽度  
        pen.setStyle(Qt.PenStyle.DashDotDotLine)                                # 5.设置线条样式
        pen.setCapStyle(Qt.PenCapStyle.RoundCap)                                # 6.设置线条连接点处的样式
        pen.setJoinStyle(Qt.PenJoinStyle.RoundJoin)                             # 7.设置线条连接处样式

        painter.setPen(pen)                                                     # 8.设置画笔对象

        p1 = QPointF(50, 50)
        p2 = QPointF(self.width() - 50, 50)
        p3 = QPointF(50, self.height() - 50)
        p4 = QPointF(self.width() - 50, self.height() - 50)
        painter.drawPolyline([p1, p2, p3, p4])                                  # 9、绘制一条折线

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

三、设置画刷

  对于封闭的图形,如矩形、圆等,用画刷 QBrush 可以在其内部填充颜色、样式、渐变、纹理或图案。用 QBrush 类创建画刷的方法如下所示。

QBrush()

QBrush(style:Qt.BrushStyle)

QBrush(brush:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage, QPixmap])

QBrush(color:Qt.GlobalColor, bs:Qt.BrushStyle=Qt.SolidPattern)
QBrush(color:Qt.GlobalColor, pixmap:Union[QPixmap, QImage, str])
QBrush(color:Union[QColor, Qt.GlobalColor, str], bs:Qt.BrushStyle=Qt.SolidPattern)
QBrush(color:Union[QColor, Qt.GlobalColor, str], pixmap:Union[QPixmap, QImage, str])

QBrush(gradient:Union[QGradient, QGradient.Preset])
QBrush(image:Union[QImage, str])
QBrush(pixmap:Union[QPixmap, QImage, str])

  QBrush 类的常用方法如下:

setStyle(style:Qt.BrushStyle) -> None                                           # 设置风格
style() -> Qt.BrushStyle                                                        # 获取风格

setTexture(pixmap:QPixmap) -> None                                              # 设置纹理图片
texture() -> QPixmap                                                            # 获取纹理图片

setTextureImage(image:QImage) -> None                                           # 设置纹理图片
textureImage() -> QImage                                                        # 获取纹理图片

setColor(color:Union[QColor, Qt.GlobalColor, str]) -> None                      # 设置颜色
color() -> QColor                                                               # 获取颜色

gradient() -> QGradient                                                         # 获取渐变色

setTransform(matrix:QTransform) -> None                                         # 设置变换矩阵
transform() -> QTransform                                                       # 获取变换矩阵

isOpaque() -> bool                                                              # 设置是否不透明

  画刷的风格setStyle(style:Qt.BrushStyle) 方法设置,其中参数 styleQt.BrushStyle 类型的枚举值,可以取值如下所示:

Qt.BrushStyle.SolidPattern
Qt.BrushStyle.Dense1Pattern
Qt.BrushStyle.Dense2Pattern
Qt.BrushStyle.Dense3Pattern
Qt.BrushStyle.Dense4Pattern
Qt.BrushStyle.Dense5Pattern
Qt.BrushStyle.Dense6Pattern
Qt.BrushStyle.Dense7Pattern
Qt.BrushStyle.HorPattern
Qt.BrushStyle.VerPattern
Qt.BrushStyle.CrossPattern
Qt.BrushStyle.BDiagPattern
Qt.BrushStyle.FDiagPattern
Qt.BrushStyle.DiagCrossPattern
Qt.BrushStyle.TexturePattern
Qt.BrushStyle.NoBrush

画刷的样式

  画刷的纹理 可以用 setTexture(texture:QPixmap)setTextureImage(texture:QImage) 方法来设置,这时 画刷的样式 被设置成 Qt.BrushStyle.TexturePattern

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import QPointF, QRectF, Qt
from PySide6.QtGui import QPainter, QPaintEvent, QBrush

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象
        brush = QBrush()                                                        # 2.创建画刷对象

        brush.setColor(Qt.GlobalColor.blue)                                     # 3.设置画刷颜色
        brush.setStyle(Qt.BrushStyle.CrossPattern)                              # 4.设置画刷样式

        painter.setBrush(brush)                                                 # 5.设置画刷

        p1 = QPointF(self.width() / 4, self.height() / 4)
        p2 = QPointF(3 * self.width() / 4, 3 * self.height() / 4)
        painter.fillRect(QRectF(p1, p2), brush)                                 # 6.填充一个矩形

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

四、渐变色

  在用画刷进行填充时,可以设置填充颜色为渐变色。所谓渐变色是指在两个不重合的点处分别设置不同的颜色,这两个点一个是起点,另一个是终点,这两个点之间的颜色从起点的颜色逐渐过渡到终点的颜色。

  定义渐变色的类是 QGradient,渐变样式分为 3 种类型,分别为 线性渐变 QLinearGradient径向渐变 QRadialGradient圆锥渐变 QConicalGradient,它们都继承自 QGradient 类,也会继承 QGradient 类的属性和方法。

渐变样式

  QLinearGradientQRadialGradientQConicalGradient 继承自 QGradient,因此也会继承 QGradient 的方法。QGradient 类的常用方法如下:

setCoordinateMode(mode:QGradient.CoordinateMode) -> None                        # 设置坐标模式
coordinateMode() -> QGradient.CoordinateMode                                    # 获取坐标模式

setColorAt(position:float, color:Union[QColor, Qt.GlobalColor, str]) -> None    # 设置颜色
setStops(stops:Sequence[Tuple[float, QColor]]) -> None                          # 设置颜色

setInterpolationMode(mode:QGradient.InterpolationMode) -> None                  # 设置插值模式
interpolationMode() -> QGradient.InterpolationMode                              # 获取插值模式

setSpread(spread:QGradient.Spread) -> None                                      # 设置扩展模式
spread() -> QGradient.Spread                                                    # 获取扩展模式

type() -> QGradient.Type                                                        # 获取类型

  在渐变区域内,可以在多个点设置颜色值,这些点之间的颜色值根据两侧的颜色来确定。在定义内部点的颜色值时,通常通过逻辑坐标来定义,渐变区域内的起始点的逻辑值是 0,终止点的逻辑值是 1。如果要在中间位置定义颜色,可以用 setColorAt(pos:float, color:Union[QColor, Qt.GlobalColor, str]) 方法来定义。我们也可以用 setStops(stops:Sequence[Tuple[float, QColor]]) 方法一次定义多个颜色值。

  用 setCoordinateMode(mode:QGradient.CoordinateMode) 方法可以设置坐标的模式,参数 QGradient.CoordinateMode 的取值如下所示:

# 逻辑方式,起始点为0,终止点为1,这是默认值
QGradient.CoordinateMode.LogicalMode

# 相对于绘图区域矩形边界的逻辑坐标,左上角的坐标是(0, 0),右下角的坐标是(1, 1)
QGradient.CoordinateMode.ObjectMode

# 相对于绘图设备矩形边界的逻辑坐标,左上角的坐标是(0, 0),右下角的坐标是(1, 1)
QGradient.CoordinateMode.StretchToDeviceMode

# 与ObjectMode基本相同,除了QBrush.transform()应用与逻辑空间而不是物理空间
QGradient.CoordinateMode.ObjectBoundingMode

  当设置的渐变区域小于填充区域时,渐变颜色可以扩展到渐变区域以外的空间。扩展模式用 setSpread(spread:QGradient.Spread) 方法定义,参数 spreadQGradient.Spread 类型的枚举值,可以取值如下所示:

QGradient.Spread.PadSpread                                                      # 用最近的颜色扩展
QGradient.Spread.RepeatSpread                                                   # 重复渐变
QGradient.Spread.ReflectSpread                                                  # 对称渐变

扩展模式不适合圆锥渐变,圆锥渐变没有固定的边界。

  用 setInterpolationMode(mode:QGradient.InterpolationMode) 方法 设置渐变色内部的插值模式,参数 modeQGradient.InterpolationMode 类型的枚举值,可以取值如下:

QGradient.InterpolationMode.ColorInterpolation
QGradient.InterpolationMode.ComponentInterpolation

  用 type() 方法可以 获取渐变类型,返回值可能如下:

QGradient.Type.LinearGradient                                                   # 线性渐变
QGradient.Type.RadialGradient                                                   # 径向渐变
QGradient.Type.ConicalGradient                                                  # 圆锥渐变
QGradient.Type.NoGradient                                                       # 无渐变色

4.1、线性渐变

  用 QLinearGradient 类创建线性渐变色的方法如下所示。

QLinearGradient()

QLinearGradient(xStart:float, yStart:float, xFinalStop:float, yFinalStop:float)

QLinearGradient(start:Union[QPointF, QPoint, QPainterPath.Element], finalStop:Union[QPointF, QPainterPath.Element])

  线性渐变 需要一个 线性渐变矩形区域(起始和终止位置),参数用于确定这个矩形区域。

  QLinearGradient 类的常用方法:

setStart(start:Union[QPontF, QPoint, QPainterPath.Element]) -> None             # 设置起始点
setStart(x:float, y:float) -> None                                              # 设置起始点
start() -> QPointF                                                              # 获取起始点

setFinalStop(stop:Union[QPontF, QPoint, QPainterPath.Element]) -> None          # 设置终止点
setFinalStop(x:float, y:float) -> None                                          # 设置终止点
finalStop() -> QPointF                                                          # 获取终止点

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import QPointF, QRectF, Qt
from PySide6.QtGui import QPainter, QPaintEvent, QPen, QBrush
from PySide6.QtGui import QLinearGradient

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        width = self.width()
        height = self.height()

        painter = QPainter(self)                                                # 1.创建绘图对象

        pen = QPen()                                                            # 2.创建钢笔对象,绘制边框
        pen.setWidth(5)                                                         # 3.设置边框宽度
        pen.setColor(Qt.GlobalColor.darkBlue)                                   # 4.设置边框颜色
        pen.setStyle(Qt.PenStyle.DashLine)                                      # 5.设置边框样式
        painter.setPen(pen)                                                     # 6.设置钢笔

        linear = QLinearGradient(QPointF(0, 0), QPointF(width / 4, height / 4)) # 7.线性渐变

        # 8.设置颜色
        linear.setStops([(0, Qt.GlobalColor.red), (0.3, Qt.GlobalColor.yellow), (0.6, Qt.GlobalColor.green), (1, Qt.GlobalColor.blue)])
        linear.setSpread(QLinearGradient.Spread.ReflectSpread)                  # 9.设置扩展模式

        brush = QBrush(linear)                                                  # 10.用线性渐变定义画刷
        painter.setBrush(brush)                                                 # 11.设置画刷
        painter.drawRect(QRectF(0, 0, width, height))                           # 12.绘制矩形

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

4.2、径向渐变

  用 QRadialGradient 类创建径向渐变色的方法如下:

QRadialGradient()

QRadialGradient(cx:float, cy:float, radius:float)
QRadialGradient(center:Union[QPointF, QPoint, QPainterPath.Element], radius:float)

QRadialGradient(cx:float, cy:float, radius:float, fx:float, fy:float)

QRadialGradient(center:Union[QPointF, QPoint, QPainterPath.Element], radius:float, focalPoint:Union[QPointF, QPoint, QPainterPath.Element])

QRadialGradient(cx:float, cy:float, centerRadius:float, fx:float, fy:float, focalRadius:float)

QRadialGradient(center:Union[QPointF, QPoint, QPainterPath.Element], centerRadius:float, focalPoint:Union[QPointF, QPoint, QPainterPath.Element], focalRadius:float)

  QRadialGradient 类的常用方法:

setCenter(center:Union[QPointF, QPoint]) -> None                                # 设置圆心
setCenter(x:float, y:float) -> None                                             # 设置圆心

setRadius(radius:float) -> None                                                 # 设置半径
setCenterRadius(radius:float) -> None                                           # 设置半径

setFocalPoint(focalPoint:Union[QPointF, QPoint, QPainterPath.Element]) -> None  # 设置焦点位置
setFocalPoint(x:float, y:float) -> None                                         # 设置焦点位置

setFocalRadius(radius:float) -> None                                            # 设置焦点半径

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import QPointF, QRectF, Qt
from PySide6.QtGui import QPainter, QPaintEvent, QPen, QBrush
from PySide6.QtGui import QRadialGradient

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        width = self.width()
        height = self.height()

        painter = QPainter(self)                                                # 1.创建绘图对象

        pen = QPen()                                                            # 2.创建钢笔对象,绘制边框
        pen.setWidth(5)                                                         # 3.设置边框宽度
        pen.setColor(Qt.GlobalColor.darkBlue)                                   # 4.设置边框颜色
        pen.setStyle(Qt.PenStyle.DashLine)                                      # 5.设置边框样式
        painter.setPen(pen)                                                     # 6.设置钢笔

        radial = QRadialGradient(QPointF(width / 2, height / 2), width / 8)     # 7.径向渐变

        # 8.设置颜色
        radial.setColorAt(0, Qt.GlobalColor.red)
        radial.setColorAt(0.3, Qt.GlobalColor.yellow)
        radial.setColorAt(0.6, Qt.GlobalColor.green)
        radial.setColorAt(1, Qt.GlobalColor.blue)

        radial.setSpread(QRadialGradient.Spread.RepeatSpread)                   # 9.设置扩展模式

        brush = QBrush(radial)                                                  # 10.用径向渐变创建画刷
        painter.setBrush(brush)                                                 # 11.设置画刷
        painter.drawRect(QRectF(0, 0, width, height))                           # 12.绘制矩形

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

4.3、圆锥渐变

  径向渐变 需要的几何参数下所示,需要确定 圆心位置半径焦点位置焦点半径。径向渐变的构造函数中,参数 center圆心位置,可以用点或坐标定义。参数 centerRadius半径;第 focalPoint 个参数是 焦点位置,可以用点或坐标定义;第 focalRadius 个参数是 焦点半径。如果焦点设置到圆的外面,则取圆上的点作为焦点。

  用 QConicalGradient 创建 圆锥渐变色 的方法如下所示:

QConicalGradient()
QConicalGradient(cx:float, cy:float, startAngle:float)
QConicalGradient(center:Union[QPointF, QPoint, QPainterPath.Element], startAngle:float)

  圆锥渐变 需要的几何参数为 圆心位置起始角度 a,角度必须在 0°~360° 之间,圆心位置可以用点或坐标来定义。

径向渐变和圆锥渐变的几何参数

  QConicalGradient 类的常用方法:

setCenter(center:Union[QPointF, QPoint]) -> None                                # 设置圆心
setCenter(x:float, y:float) -> None                                             # 设置圆心

setAngle(angle:float) -> None                                                   # 设置起始角度

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import QPointF, QRectF, Qt
from PySide6.QtGui import QPainter, QPaintEvent, QPen, QBrush
from PySide6.QtGui import QConicalGradient

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        width = self.width()
        height = self.height()

        painter = QPainter(self)                                                # 1.创建绘图对象

        pen = QPen()                                                            # 2.创建钢笔对象,绘制边框
        pen.setWidth(5)                                                         # 3.设置边框宽度
        pen.setColor(Qt.GlobalColor.darkBlue)                                   # 4.设置边框颜色
        pen.setStyle(Qt.PenStyle.DashLine)                                      # 5.设置边框样式
        painter.setPen(pen)                                                     # 6.设置钢笔

        conical = QConicalGradient(QPointF(width / 2, height / 2), height / 8)  # 7.圆锥渐变

        conical.setAngle(60)                                                    # 8.设置开始角度

        # 9.设置颜色
        conical.setColorAt(0, Qt.GlobalColor.red)
        conical.setColorAt(0.3, Qt.GlobalColor.yellow)
        conical.setColorAt(0.6, Qt.GlobalColor.green)
        conical.setColorAt(1, Qt.GlobalColor.blue)

        brush = QBrush(conical)                                                 # 10.创建画刷
        painter.setBrush(brush)                                                 # 11.设置画刷
        painter.drawRect(QRectF(0, 0, width, height))                           # 12.绘制矩形

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

五、绘制几何图形

5.1、绘制点

  QPainter 可以一次绘制一个点,也可以一次绘制多个点,其中 QPolygonQPolygonF 是用于存储多个 QPointQPointF 的类。

# 绘制单点
drawPoint(x:int, y:int) -> None
drawPoint(p:QPoint) -> None
drawPoint(pt:Union[QPointF, QPoint]) -> None
drawPoint(pt:QPainterPath.Element) -> None

# 绘制多点
drawPoints(points:Sequence[QPointF]) -> None
drawPoints(points:Sequence[QPoint]) -> None
drawPoints(points:Union[QPolygon, Sequence[QPoint], QRect])
drawPoints(points:Union[QPolygon, Sequence[QPoint], QPolygon, QRectF])

  创建 QPolygon 实例的方法如下:

QPolygon()
QPolygon(points:Sequence[QPoint])

  创建 QPolygonF 实例的方法如下:

QPolygonF()
QPolygonF(points:Sequence[Union[QPointF,QPoint]])

  用 QPolygonappend(point:QPoint) 方法可以 添加点,用 insert(pos:int,point:QPoint) 方法可以 插入点,用 setPoint(pos:int,point:QPoint) 方法可以 更改点。用 QPolygonFappend(point:Union[QPointF,QPoint]) 方法可以 添加点,用 insert(pos:int, point:Union[QPointF,QPoint]) 方法可以 插入点

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import QPointF
from PySide6.QtGui import QPainter, QPaintEvent, QPen

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象

        pen = QPen()                                                            # 2.创建钢笔对象
        pen.setColor("red")                                                     # 3.设置钢笔的颜色
        pen.setWidth(10)                                                        # 4.设置钢笔的宽度
        painter.setPen(pen)                                                     # 5.设置钢笔

        painter.drawPoint(QPointF(self.width() / 2, self.height() / 2))         # 6.绘制点

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

5.2、绘制直线

  绘制直线需要用两个点。可以一次绘制一条直线,也可一次绘制多条直线,其中 QLineQLineF 是 2D 直线类。

# 绘制单条直线
drawLine(line:QLine) -> None
drawLine(line:Union[QLineF, QLine]) -> None
drawLine(p1:QPoint, p2:QPoint) -> None
drawLine(p1:Union[QPointF, QPoint], p2:Union[QPointF, QPoint]) -> None
drawLine(x1:int, y1:int, x2:int, y2:int) -> None

# 绘制多条直线
drawLines(lines:Sequence[QLine]) -> None
drawLines(lines:Sequence[QLineF]) -> None
drawLines(pointPairs:Sequence[QPoint]) -> None
drawLines(pointPairs:Sequence[QPointF]) -> None

  用 QLine 类定义直线实例的方法如下:

QLine()
QLine(p1:QPoint, p2:QPoint)
QLine(x1:int, y1:int, x2:int, y2:int)

  用 QLineF 类定义直线实例的方法如下:

QLineF()
QLineF(line:QLine)
QLineF(p1:Union[QPointF,QPoint], p2:Union[QPointF,QPoint])
QLineF(x1:float, y1:float, x2:float, y2:float)

  用 QLinesetLine(x1:int, y1:int, x2:int, y2:int) 方法、setP1(point:QPoint) 方法、setP2(point:QPoint)setPoints(p1:QPoint, p2:QPoint) 方法可以 设置线两端的点QLineF 也有同样的方法,只需把参数 int 改成 float,或 QPoint 改成 QPointF

  在绘制几何图像和文字时,如果线条是斜线,对线条进行放大后会发现它呈现锯齿状。为防止出现锯齿状,需要对线条边缘进行模糊化处理。用 QPaintersetRenderHint(hint:QPainter.RenderHint, on:bool=True)setRenderHints(hints:QPainter.RenderHints, on:bool=True) 方法可以 设置是否进行抗锯齿处理,用 testRenderHint(hint:QPainter.RenderHint) 方法可以 获取是否设置了抗锯齿算法,其中参数 hindQPainter.RenderHint 类型的枚举值,可以取值如下:

QPainter.RenderHint.Antialiasing                                                # 启用抗锯齿
QPainter.RenderHint.TextAntialiasing                                            # 对文本进行抗锯齿
QPainter.RenderHint.SmoothPixmapTransform                                       # 使用平滑的像素图像算法
QPainter.RenderHint.LosslessImageRendering                                      # 用于PDF文档

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import QPointF
from PySide6.QtGui import QPainter, QPaintEvent, QPen

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象

        pen = QPen()                                                            # 2.创建画笔对象
        pen.setColor("red")                                                     # 3.设置钢笔的颜色
        pen.setWidth(10)                                                        # 4.设置画笔宽度
        painter.setPen(pen)                                                     # 5.设置绘图对象画笔

        painter.drawLine(QPointF(0, 0), QPointF(self.width(), self.height()))   # 6.绘制直线
        painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)           # 7.抗锯齿

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

5.3、绘制折线

  绘制折线必须用两个点,即使两条折线的终点和起始点相同,每条折线也必须用两个点来定义。折线由多个折线段构成,绘制折线需要给出多个点,上个折线段的终点是下个折线段的起始点。

drawPolyline(points:Sequence[QPoint]) -> None
drawPolyline(points:Sequence[QPointF]) -> None

drawPolyline(polygon:Union[QPolygon, Sequence[QPoint], QRect]) -> None
drawPolyline(polygon:Union[QPolygonF, Sequence[QPointF], QRectF]) -> None

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import QPointF, Qt
from PySide6.QtGui import QPainter, QPaintEvent, QPen

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象

        pen = QPen()                                                            # 2.创建画笔对象
        pen.setColor("red")                                                     # 3.设置钢笔的颜色
        pen.setWidth(10)                                                        # 4.设置画笔宽度
        pen.setJoinStyle(Qt.PenJoinStyle.RoundJoin)                             # 5.设置画笔连接样式
        pen.setCapStyle(Qt.PenCapStyle.RoundCap)                                # 6.设置画笔端点样式
        painter.setPen(pen)                                                     # 7.设置绘图对象画笔

        p1 = QPointF(10, 10)
        p2 = QPointF(self.width() - 10, 10)
        p3 = QPointF(10, self.height() - 10)
        p4 = QPointF(self.width() - 10, self.height() - 10)

        painter.drawPolyline([p1, p2, p3, p4])                                  # 8.绘制折线

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

5.4、绘制矩形

  QPainter 可以一次绘制一个矩形,也可以一次绘制多个矩形。

# 绘制单个矩形
drawRect(rect:QRect) -> None
drawRect(rect:Union[QRect, QRectF]) -> None
drawRect(x:int, y:int, width:int, height:int) -> None

# 绘制多个矩形
drawRects(rectangles:Sequence[QRect]) -> None
drawRects(rectangles:Sequencep[QRectF]) -> None

  其中 drawRect(x:int, y:int, width:int, heigth:int) 方法中 xy 参数确定 左上角的位置widthheight 参数确定 宽度高度

  圆角矩形是在矩形的基础上对 4 个角分别用一个椭圆进行倒圆角。要绘制圆角矩形,除了需要设置绘制矩形的参数外,还需要设置椭圆的两个半径。

圆角矩形

  QPainter 绘制椭圆的方法如下:

drawRoundedRect(rect:Union[QRectF,QRect], xRadius:float, yRadius:float, mode:Qt.SizeMode=Qt.AbsoluteSize) -> None
drawRoundedRect(x:int, y:int, w:int, h:int, xRadius:float, yRadius:float, mode:Qt.SizeMode=Qt.AbsoluteSize) -> None

  其中参数 modeQt.SizeMode 类型的枚举值,可以取值如下:

Qt.SizeMode.AbsoluteSize                                                        # 椭圆半径是绝对值
Qt.SizeMode.RelativeSize                                                        # 椭圆半径是相对于矩形边长的相对值

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import Qt, QRect
from PySide6.QtGui import QPainter, QPaintEvent, QPen

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象

        pen = QPen()                                                            # 2.创建画笔对象
        pen.setColor("red")                                                     # 3.设置钢笔的颜色
        pen.setWidth(10)                                                        # 4.设置画笔宽度
        painter.setPen(pen)                                                     # 5.设置绘图对象画笔

        # 6.绘制矩形
        painter.drawRect(QRect(10, 10, self.width() - 20, self.height() // 2 - 20))

        # 7.绘制圆角矩形
        painter.drawRoundedRect(QRect(10, self.height() // 2 + 10, self.width() - 20, self.height() // 2 - 20), 50, 30, Qt.SizeMode.AbsoluteSize)


if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

5.5、绘制椭圆

  一个椭圆有两个半径。确定一个椭圆有两种方法:一种是先确定一个矩形边界,在矩形内部作一个与矩形相切的内切椭圆;另一种是先定义一个中心,再定义两个半径。如果矩形边界是正方形或者椭圆的两个半径相等,椭圆就变成了圆。扇形是椭圆的一部分,绘制扇形时除了确定椭圆的几何数据外,还需要确定扇形的起始角和跨度角。需要特别注意的是,起始角和跨度角都是用输入值的 1/16 计算。

椭圆和扇形几何示意图

# 绘制椭圆
drawEllipse(center:[QPoint, QPointF], rx:int, ry:int) -> None
drawEllipse(r:QRect) -> None
drawEllipse(r:Union[QRect, QRectF]) -> None
drawEllipse(x:int, y:int, w:int, h:int) -> None
drawEllipse(center:QPainterPath.Element, rx:float, ry:float) -> None

# 绘制扇形
drawPie(rect:Union[QRect, QRectF], a:int, alen:int) -> None
drawPie(x:int, y:int, w:int, h:int, a:int, alen:int) -> None

  绘制弧和绘制弦的参数与绘制扇形的参数相同,只不过是从椭圆上截取的部分不同。QPainter 绘制弧和弦的方法如下:

# 绘制弧
drawArc(rect:Union[Qrect, QRectF], a:int, alen:int) -> None
drawArc(x:int, y:int, w:int, h:int, a:int, alen:int) -> None

# 绘制弦
drawChord(rect:Union[QRect, QRectF], a:int, alen:int) -> None
drawChord(x:int, y:int, w:int, h:int, a:int, alen:int) -> None

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import Qt, QRect
from PySide6.QtGui import QPainter, QPaintEvent, QPen

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象

        pen = QPen()                                                            # 2.创建画笔对象
        pen.setColor("red")                                                     # 3.设置钢笔的颜色
        pen.setWidth(10)                                                        # 4.设置画笔宽度
        painter.setPen(pen)                                                     # 5.设置绘图对象画笔

        # 6.绘制椭圆
        painter.drawEllipse(QRect(10, 10, self.width() // 2 - 20, self.height() // 2 - 20))

        # 7.绘制扇形
        painter.drawPie(QRect(self.width() // 2, self.height() // 2, self.width() // 2 - 20, self.height() // 2 - 20), 45 * 16, 60* 16)


if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

5.6、绘制多边形

  QPainter 绘制多边形和凸多边形的方法如下所示。

# 绘制多边形
drawPolygon(points:Sequence[QPoint], fill:Qt.FillRule) -> None
drawPolygon(points:Sequence[QPointF], fill:Qt.FillRule) -> None

drawPolygon(polygon:Union[QPolygon, Sequence[QPoint], QRect], fillRule:Qt.FillRule=Qt.OddEvenFill) -> None

drawPolygon(polygon:Union[QPolygonF, Sequence[QPointF], QPolygon, QRectF], fill:Qt.FillRule=Qt.OddEvenFill) -> None

# 绘制凸多边形
drawConvexPolygon(polygon:Union[QPolygon, Sequence[QPoint], QRect]) -> None
drawConvexPolygon(polygon:Union[QPolygonF, Sequence[QPointF], QPolygon, QRectF]) -> None

  使用这些方法时,需要给出多边形或凸多边形的顶点,系统会自动在起始点和终止点之间建立直线,使多边形封闭。参数 fillQt.FillRule 的枚举类型,用于确定一个点是否在图形内部,在内部的区域可以进行填充。fillRule 可以取值如下:

  • Qt.FillRule.OddEvenFill奇偶填充规则,要判断一个点是否在图形中,可以从该点向图形外引一条水平线,如果该水平线与图形的交点个数为奇数,那么该点在图形中。
  • Qt.FillRule.WindingFill非零绕组填充规则,要判断一个点是否在图形中,可以从该点向图形外引一条水平线,如果该水平线与图形的边线相交,这个边线是顺时针绘制的,就记为 1,是逆时针绘制的就记为 -1,然后将所有数值相加,若结果不为 0,那么该点就在图形中。

填充规则

import sys
import math

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import Qt, QPointF
from PySide6.QtGui import QPainter, QPaintEvent, QPen, QBrush

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象

        pen = QPen()                                                            # 2.创建画笔对象
        pen.setColor("red")                                                     # 3.设置钢笔的颜色
        pen.setWidth(10)                                                        # 4.设置画笔宽度
        painter.setPen(pen)                                                     # 5.设置绘图对象画笔

        # 6、设置画刷
        brush = QBrush(Qt.BrushStyle.SolidPattern)
        painter.setBrush(brush)

        r = 100
        x = self.width() / 4
        y = self.height() / 4

        p1 = QPointF(r * math.cos(-90 * math.pi / 180) + x, r * math.sin(-90 * math.pi / 180) + y)
        p2 = QPointF(r * math.cos(-18 * math.pi / 180) + x, r * math.sin(-18 * math.pi / 180) + y)
        p3 = QPointF(r * math.cos(54 * math.pi / 180) + x, r * math.sin(54 * math.pi / 180) + y)
        p4 = QPointF(r * math.cos(126 * math.pi / 180) + x, r * math.sin(126 * math.pi / 180) + y)
        p5 = QPointF(r * math.cos(198 * math.pi / 180) + x, r * math.sin(198 * math.pi / 180) + y)

        # 7.绘制多边形
        painter.drawPolygon([p1, p3, p5, p2, p4], Qt.FillRule.OddEvenFill)

        offset = QPointF(self.width() / 2, 0)
        painter.drawPolygon([p1 + offset, p3 + offset, p5 + offset, p2 + offset, p4 + offset], Qt.FillRule.WindingFill)

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

六、绘图路径

  为了将简单的图形组合成复杂且封闭的图形,需要用到绘图路径 QPainterPath,前面介绍的绘图方法所绘制的图形都可以加入 QPainterPath 中,构成 QPainterPath 的元素。用 QPainterdrawPath(path:QPainterPath) 方法或 strokePath(path:QPainterPath, pen:Union[QPen, Qt.PenStyle, QColor]) 方法可以 将绘图路径的图形绘制出来,用绘图路径绘制的图形不论是否封闭,都隐含是封闭的,可以在其内部进行填充。

  QPainterPath 是一些绘图命令按照先后顺序的有序组合,创建一次后可以反复使用。用 QPainterPath 类创建绘图路径实例对象的方法如下所示:

QPainterPath()
QPainterPath(other:QPainterPath)
QPainterPath(startPoint:Union[QPoint, QPointF, QPainterPath.Element])

  其中 startPoint绘制路径的起始点,也可以用绘图路径的 moveTo(point:Union[QPointF,QPoint])moveTo(x:float, y:float) 方法 将绘图路径的当前点移到起始点

  QPainterPath 类与绘图相关的方法:

currentPosition() -> QPointF                                                    # 获取当前的起始点QPointF

# 将当前点移动到指定的点,作为下一个绘图单元的起始点
moveTo(p:Union[QPoint, QPointF]) -> None
moveTo(x:float, y:float) -> None

# 将当前点移动到指定矩形框内的椭圆上,angle是起始角度
arcMoveTo(rect:Union[QRect, QRectF], angle:float) -> None
arcMoveTo(x:float, y:float, w:float, h:float, angle:float) -> None

# 在当前点与指定点之间绘制直线
lineTo(p:Union[QPoint, QPointF, QPointerPath.Element]) -> None
lineTo(x:float, y:float) -> None

# 在当前点和终点间绘制三次贝塞尔曲线,前两个点是中间控制点,最后一个点是终点
cubicTo(ctrlPt1:Union[QPoint, QPointF, QPainterPath.Element], ctrlPt2:Union[QPoint, QPointF, QPainterPath.Element], endPty:Union[QPoint, QPointF, QPainterPath.Element]) -> None
cubicTo(ctrlPt1x:float, ctrlPt1y:float, ctrlPt2x:float, ctrlPt2y:float, endPtx:float, endPty:float) -> None

# 在当前点和终点间添加二次贝塞尔曲线,第一个点是控制点
quadTo(ctrlPt:Union[QPoint, QPointF, QPointerPath.Element], endPt:Union[QPoint, QPointF, QPointerPath.Element]) -> None
quadTo(ctrlPtx:float, ctrlPty:float, endPtx:float, endPty:float) -> None

# 在矩形框内绘制圆弧,startAngle和arcLength分别是起始点和跨度角
arcTo(rect:Union[QRect, QRectF], startAngle:float, arcLength:float) -> None
arcTo(x:float, y:float, w:float, h:float, startAngle:float, arcLength:float) -> None

# 绘制封闭的椭圆
addEllipse(rect:Union[QRect, QRectF]) -> None
addEllipse(center:Union[QPoint, QPointF], rx:float, ry:float) -> None
addEllipse(x:float, y:float, w:float, h:float) -> None

# 绘制矩形
addRect(rect:Union[QRect, QRectF]) -> None
addRect(x:float, y:float, w:float, h:float) -> None

# 绘制圆角矩形
addRoundedRect(rect:Union[QRect, QRectF], xRadius:float, yRadius:float, mode:Qt.SizeMode=Qt.AbsoluteSize) -> None
addRoundedRect(x:float, y:float, w:float, h:float, xRadius:float, yRadius:float, mode:Qt.SizeMode=Qt.AbsoluteSize) -> None

# 绘制多边形
addPolygon(polygon:Union[QPolygon, QPolygonF, QPointF, Sequence[QPointF]]) -> None

# 绘制文本
addText(point:Union[QPoint, QPointF, QPainterPath.Element], f:Union[QFont, str, Sequence[str]], text:str) -> None
addText(x:float, y:float, f:Union[QFont, str, Sequence[str]], text:str) -> None

addRegion(region:Union[QRegion, QBitmap, QPolygon, QRect]) -> None              # 绘制QRegion的范围

addPath(path:QPainterPath) -> None                                              # 将其它绘图路径添加进来

# 将绘图路径进行平移
translate(offset:Union[QPoint, QPointF, QPainterPath.Element]) -> None
translate(dx:float, dy:float)

closeSubpath() -> None                                                          # 有当前子路径的首尾绘制直线,开始新的子路径的绘制
connectPath(path:QPainterPath) -> None                                          # 由当前路径的终点位置与给定路径的起始位置绘制直线

  QPainterPath 类与查询相关的方法:

angleAtPercent(t:float) -> float                                                # 获取绘图路径长度百分比处的切向角
slopeAtPercent(t:float) -> float                                                # 获取斜率 
boundingRect() -> QRectF                                                        # 获取路径所在的边界矩形区域
capacity() -> int                                                               # 获取路径中单元的数量
elementCount() -> int                                                           # 获取绘图路径的单元数量
clear() -> None                                                                 # 清空绘图路径中的元素

contains(p:Union[QPoint, QPointF]) -> bool                                      # 如果指定的点在路径内部,则返回True
contains(rect:QRect) -> bool                                                    # 如果路径包含指定的矩形,则返回True
contains(pt:QPainterPath.Element) -> bool                                       # 如果包含指定的路径,则返回True

controlPointRect() -> QRectF                                                    # 获取包含路径中所有点和控制点构成的矩形

intersected(r:QPainterPath) -> QPainterPath                                     # 获取绘图路径和指定路径填充区域相交的路径
united(r:QPainterPath) -> QPainterPath                                          # 获取绘图路径与指定路径填充区域合并的路径
subtracted(r:QPainterPath) -> QPainterPath                                      # 获取减去指定路径后的路径

intersects(p:QPainterPath) -> bool                                              # 获取绘图路径与指定路径是否相交
intersects(rect:QRectF) -> bool                                                 # 获取绘图路径与矩形区域是否相交
isEmpty() -> bool                                                               # 获取绘图路径是否为空
length() -> float                                                               # 获取绘图路径的长度
pointAtPercent(t:float) -> QPointF                                              # 获取指定长度百分比处的点

reserve(size:int) -> None                                                       # 在内存中预留指定数量的绘图单元内存空间

setElementPositionAt(i:int, x:float, y:float) -> None                           # 将索引是i的元素的x和y坐标设置成指定值
setFillRule(fillRule:Qt.FillRule) -> None                                       # 设置填充规则

simplified() -> QPainterPath                                                    # 获取简化后的路径,如果路径元素有交叉或重合,则简化后的路径没有重合

swap(other:QPainterPath) -> None                                                # 交换绘图路径

toReversed() -> QPainterPath                                                    # 获取反转后的路径
toSubpathPolygons(matrix:QTransform=QTransform()) -> List[QPolygonF]            # 将每个元素转换成QPolygonF

translated(offset:Union[QPoint, QPointF]) -> QPainterPath                       # 获取平移后的绘图路径
translated(dx:float, dy:float) -> QPainterPath                                  # 获取平移后的绘图路径

  路径是由多个图形构成的,每个图形中可能包括直线、贝塞尔曲线、弧、椭圆、多边形、矩形或文本。使用 moveTo() 方法把当前路径移到指定位置,作为绘图开始的起点位置,移动当前点会启用一个新的子路径,并自动封闭之前的路径。

  用 lineTo() 方法 绘制直线,用 arcTo() 方法 绘制弧,用 quadTo() 方法和 cubicTo() 方法 绘制二次和三次贝塞尔曲线,用 addEllipse() 方法 绘制封闭的椭圆,用 addPolygon() 方法 绘制多边形,用 addRect() 方法和 addRoundedRect() 方法 绘制矩形。在添加直线、弧或贝塞尔曲线后,当前点移动到这些元素的最后位置。绘制弧时,弧的零度角与钟表的 3 时方向相同,逆时针方向为正。

  路径中每个绘图步骤称为 单元,比如 moveTo()lineTo()arcTo() 都是 单元addRect()addPolygon() 等都是用 moveTo()lineTo()arcTo() 等绘制的。例如 addRect(100, 50, 200, 200)movetTo(100, 50)lineTo(300, 50)lineTo(300, 250)lineTo(100, 250)lineTo(100, 50) 共 5 个单元构成。

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtCore import QPointF, Qt
from PySide6.QtGui import QPainter, QPaintEvent, QPen
from PySide6.QtGui import QPainterPath

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        center = QPointF(self.width() / 2, self.height() / 2)
        r = min(self.width() , self.height()) / 3

        painter = QPainter(self)                                                # 1.创建绘图对象

        pen = QPen()                                                            # 2.创建画笔
        pen.setWidth(10)                                                        # 3.设置画笔宽度
        pen.setColor(Qt.GlobalColor.black)                                      # 4.设置画笔颜色
        painter.setPen(pen)                                                     # 5.使用钢笔对象

        path = QPainterPath()                                                   # 6.创建路径
        path.moveTo(center)                                                     # 7.将当前点移动到指定点,作为起始点
        path.arcTo(center.x() - r, center.y() - r, 2 * r, 2 * r, 0, 360)        # 8.绘制圆弧
        path.setFillRule(Qt.FillRule.WindingFill)                               # 9.设置填充方式

        painter.drawPath(path)                                                  # 10.绘制路径 

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

七、绘制文本

  可以在指定位置绘制文本,绘制文本时,通常需要先用 setFont(font:QFont) 方法 设置 QPainter 的字体。绘制文本的方法如下所示,所绘文本默认是反锯齿的。

drawStaticText(left:int, top:int, staticText:QStaticText) -> None

drawStaticText(topLeftPosition:Union[QPoint, QPointF, QPainterPath.Element], staticText:QStaticText) -> None

drawText(p:QPoint, s:str) -> None
drawText(p:Union[QPoint, QPointF, QPainterPath.Element], s:str) -> None

drawText(x:int, y:int, s:str) -> None

drawText(r:Union[QRect, QRectF], flags:int, text:str) -> None
drawText(x:int, y:int, w:int, h:int, flags:int, text:str) -> None

  绘制文本可以用 drawStaticText() 方法,该方法比较快,且每次不用重新计算文本的排列位置。QStaticText静态文本类,用 QStaticText 类创建静态文本的方法是 QStaticText()QStaticText(text:str)。可以用 QStatciTextsetText(text:str) 方法 设置文本

  可以用 setTextFormat(format:Qt.TextFormat) 方法 设置静态文本的格式,参数 formatQt.TextFormat 类型的枚举值,可以取值如下:

Qt.TextFormat.PlainText
Qt.TextFormat.RichText
Qt.TextFormat.AutoText
Qt.TextFormat.MarkdownText

  如果所绘制的文本用当前的字体绘制时,给定的矩形范围不合适,可以用 boundingRect() 方法 获取边界矩形

boundingRect(rect:QRect, flags:int, text:str) -> QRect
boundingRect(rect:Union[QRectF, QRect], flags:int, text:str) -> QRectF
boundingRect(rect:Union[QRectF, QRect], text:str, alignmeng:Qt.Alignment) -> QRect
boundingRect(x:int, y:int, width:int, height:int, flags:int, text:str) -> QRect

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPaintEvent, QPen

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象

        font = painter.font()                                                   # 2.获取字体对象
        font.setFamily("楷体")                                                   # 3.设置字体名称
        font.setPointSize(50)                                                   # 4.设置字体大小
        font.setBold(True)                                                      # 5.设置字体是否加粗
        font.setItalic(True)                                                    # 6.设置字体是否斜体
        painter.setFont(font)                                                   # 7.使用字体对象

        pen = QPen()                                                            # 8.创建画笔对象
        pen.setColor("red")                                                     # 9.设置钢笔的颜色
        pen.setWidth(10)                                                        # 10.设置画笔宽度
        painter.setPen(pen)                                                     # 11.设置绘图对象画笔

        painter.drawText(10, 100, "你好,世界!")                                 # 12.绘制文本

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

八、填充图形

  用 QPainter 绘图时,如果所绘制的图形是封闭的,且为 QPainter 设置了画刷,则系统自动在封闭的图形内填充画刷的图案,封闭的图形包括绘图路径、矩形、椭圆、多边形。除此之外,还可以为指定的矩形范围填充图案,此时不需要有封闭的边界线。

  QPainter 类的用来填充的常用方法如下:

# 为指定的路径填充颜色
fillPath(path:QPainterPath, brush:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage, QPixmap]) -> None

# 用画刷填充指定的矩形区域
fillRect(path:Union[QRect, QRectF], brush:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, str, QGradient, QImage, QPixmap]) -> None

# 用颜色和渐变色填充指定的矩形区域
fillRect(x:int, y:int, width:int, height:int, color:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, str, QGradient, QImage, QPixmap]) -> None

# 擦除指定区域的填充
eraseRect(rect:Union[QRect, QRectF]) -> None
eraseRect(x:int, y:int, width:int, height:int) -> None

setBackground(bg:Union[QBrush, QColor, Qt.GlobalColor, QGradient]) -> None      # 设置背景色
background() -> QBrush                                                          # 获取背景画刷
setBackgroundMode(mode:Qt.BGMode) -> None                                       # 设置背景模式

setBrushOrigin(x:int, y:int) -> None                                            # 设置画刷的起始点
setBrushOrigin(point:Union[QPoint, QPointF, QPainterPath.Element]) -> None      # 设置画刷的起始点
brushOrigin() -> QPoint                                                         # 获取起始点QPoint

  用 fillRect() 方法可以 给指定的矩形区域绘制填充颜色,这时无须封闭的空间,也不会绘制出轮廓。用 eraseRect() 方法可以 擦除矩形区域的填充

  用 setBackgroundMode(mode:Qt.BGMode) 方法 设置背景的模式,其中参数 modeQt.BGMode 类型的枚举值,可以取值如下:

Qt.BGMode.TransparentMode                                                       # 透明模式
Qt.BGMode.OpaqueMode                                                            # 不透明模式

  用 setBackground(color:Union[QBrush, QColor, Qt.GlobalColor, QGradient]) 方法 设置背景色,背景色只有在不透明模式下才起作用。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPaintEvent
from PySide6.QtGui import QLinearGradient, QPen, QBrush
from PySide6.QtCore import QPointF, Qt

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):

        painter = QPainter(self)                                                # 1.创建绘图对象

        font = painter.font()                                                   # 2.获取字体对象
        font.setFamily("楷体")                                                   # 3.设置字体名称
        font.setPointSize(50)                                                   # 4.设置字体大小
        font.setBold(True)                                                      # 5.设置字体是否加粗
        painter.setFont(font)                                                   # 6.使用字体对象

        linear1 = QLinearGradient(QPointF(0, 0), QPointF(self.width(), self.height()))  # 7.使用线性渐变充当文字颜色
        # 8.设置文件线性渐变的颜色
        linear1.setStops([(0, Qt.GlobalColor.red), (0.3, Qt.GlobalColor.yellow), (0.6, Qt.GlobalColor.green), (1, Qt.GlobalColor.blue)])
        linear1.setSpread(QLinearGradient.Spread.ReflectSpread)                 # 9.设置扩展模式

        brush1 = QBrush(linear1)                                                # 10.用线性渐变定义画刷

        pen = QPen()                                                            # 11.定义画笔  
        pen.setBrush(brush1)                                                    # 12.将画刷设置给画笔
        painter.setPen(pen)                                                     # 13.设置绘图对象画笔

        painter.setBackgroundMode(Qt.BGMode.OpaqueMode)                         # 14.设置背景模式不透明

        linear2 = QLinearGradient(QPointF(0, 0), QPointF(self.width(), self.height()))  # 15.使用线性渐变充当文字背景颜色
        # 16.设置颜色
        linear2.setStops([(0, Qt.GlobalColor.blue), (0.3, Qt.GlobalColor.green), (0.6, Qt.GlobalColor.red), (1, Qt.GlobalColor.white)])
        linear2.setSpread(QLinearGradient.Spread.ReflectSpread)                 # 17.设置扩展模式

        brush2 = QBrush(linear2)                                                # 18.用线性渐变定义画刷

        painter.setBackground(brush2)                                           # 19.设置背景画刷
        painter.setBrushOrigin(0, 0)                                            # 20.设置画刷的起始点

        painter.drawText(100, 100, "你好,世界!")                                # 21.绘制字体

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

九、绘制图像

  QPainter 还可以把 QPixmapQImageQPicture图像直接绘制在绘图设备上

【1】、QPixmap 图像

  绘制 QPixmap 图像的方法如下所示,可以将图像按照原始尺寸显示,也可以缩放图像到一个矩形区域中显示,还可以从原图像上截取一部分绘制到一个矩形区域。

# 指定绘图设备上的一个点作为左上角,按照图像原始尺寸显示
drawPixmap(p:Union[QPoint, QPointF, QPainterPath.Element], pm:Union[QPixmap, QImage, str]) -> None
drawPixmap(x:int, y:int, pm:Union[QPixmap, QImage, str]) -> None

# 指定绘图设备上的矩形区域,以缩放尺寸方式显示
drawPixmap(r:QRect, pm:Union[QPixmap, QImage, str]) -> None
drawPixmap(x:int, y:int, w:int, h:int, pm:Union[QPixmap, QImage, str]) -> None

# 指定绘图设备上的一个点和图像的矩形区域,裁剪显示图像
drawPixmap(p:Union[QPoint, QPointF, QPainterPath.Element], pm:Union[QPixmap, QImage, str], sr:Union[QRect, QRectF]) -> None
drawPixmap(x:int, y:int, pm:Union[QPixmap, QImage, str], sx:int, sy:int, sw:int, sh:int) -> None

# 指定绘图设备上的矩形区域和图像的矩形区域,裁剪并缩放显示图像
drawPixmap(targetRect:Union[QRect, QRectF], pixmap:Union[QPixmap, QImage, str], sourceRect:Union[QRect, QRectF]) -> None
drawPixmap(x:int, y:int, w:int, h:int, pm:Union[QPixmap, QImage, str], sx:int, sy:int, sw:int, sh:int) -> None

# 以平铺方式绘制图片
drawTiledPixmap(x:int, y:int, w:int, h:int, pm:Union[QPixmap, QImage, str], sx:int=0, sy:int=0) -> None
drawTiledPixmap(rect:QRect, pm:Union[QPixmap, QImage, str], pos:QPoint=QPoint()) -> None
drawTiledPixmap(rect:Union[QRect, QRectF], pm:Union[QPixmap, QImage, str], offset:Union[QPoint, QPointF, QPainterPath.Element]=QPointF()) -> None

# 绘制图像的多个部分,可以对每个部分进行缩放、旋转操作
drawPixmapFragments(fragments:list[QPainter.PixmapFragment], fragmentCount:int, pixmap:Union[QPixmap, QImage, str], hints:QPainter.PixmapFragmentHints=QPainter.PixmapFragmentHints()) -> None

  用 drawPixmapFragments(fragments:list[QPainter.PixmapFragment], fragmentCount:int, pixmap:Union[QPixmap, QImage, str], hints:QPainter.PixmapFragmentHints) 方法可以 截取图像的多个区域,并对每个区域进行缩放、旋转操作,其中参数 hints 只能取 QPainter.PixmapFragmentHints.OpaqueHint。参数 QPainter.PixmapFragment 的创建方法如下:

QPainter.PixmapFragment.create(pos:QPointF,sourceRect:QRectF, scaleX:int=1, scaleY:int=1, rotation:int=0, opacity:int=1)

  其中 pos图像绘制地点sourceRect截取的图像的部分区域scaleXscaleY缩放比例rotation旋转角度opacity不透明度值

【2】、QImage 图像

  绘制 QImage 图像的方法如下所示。可以将图像按照原始尺寸显示,也可以缩放图像到一个矩形区域中显示,还可以从原图像上截取一部分绘制到一个矩形区域。

# 在指定位置,按图像实际尺寸显示
drawImage(p:Union[QPoint, QPointF, QPainterPath.ELement], image:Union[QImage, str]) -> None

# 在指定矩形区域内,图像进行缩放显示
drawImage(r:Union[QRect, QRectF], image:Union[QImage, str]) -> None

# 在指定位置,从图像上截取一部分显示
drawImage(p:Union[QPoint, QPointF, QPainterPath.Element], image:Union[QImage, str], sr:Union[QRect, QRectF], flags:Qt.ImageConversionFlags=Qt.AutoColor) -> None
drawImage(x:int, y:int, image:Union[QImage, str], sx:int=0, sy:int=0, sw:int=-1, sh:int=-1, flags:Qt.ImageConversionFlags=Qt.AutoColor) -> None

# 从图像上截取一部分,以缩放形式显示在指定的矩形区域内
drawImage(targetRect:Union[QRect, QRectF], image:Union[QImage, str], sourceRect:Union[QRect, QRectF], flags:Qt.ImageConversionFlags=Qt.AutoColor) -> None

  其中 flags 参数是 Qt.ImageConversionFlags 枚举值,可取值如下:

Qt.ImageConversionFlags.AutoColor
Qt.ImageConversionFlags.ColorOnly
Qt.ImageConversionFlags.MonoOnly

【3】、QPicture 图像

  对于 QPicture 图像,只能在绘图设备的指定点上按照原始尺寸进行绘制。绘制 QPicture 图像的方法如下:

drawPicture(x:int, y:int, picture:Union[QPicture,int]) -> None
drawPicture(p:Union[QPointF, QPoint, QPainterPath.Element], picture:Union[QPicture,int]) -> None

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPaintEvent, QImage

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象

        image = QImage("assets/images/1.jpg")                                   # 2.创建图像对象
        painter.drawImage(self.rect(), image)                                   # 3.绘制图像

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

十、裁剪区域

  当所绘图形比较大时,若只想显示绘图上的一部分区域的内容,其他区域的内容不显示,就需要使用裁剪区域。用 QPainter 设置裁剪区域的方法下所示:

setClipping(enable:bool) -> None                                                # 设置是否启动裁剪区域
hasClipping() -> bool                                                           # 获取是否有裁剪区域

setClipPath(path:QPainterPath, op:Qt.ClipOperation=Qt.ReplaceClip) -> None      # 用路径设置裁剪区域
clipPath() -> QPainterPath                                                      # 获取裁剪区域的路径

setClipRect(rect:Union[QRect, QRectF], op:Qt.ClipOperation=Qt.ReplaceClip) -> None      # 用矩形框设置裁剪区域
setClipRect(x:int, y:int, w:int, h:int, op:Qt.ClipOperation=Qt.ReplaceClip) -> None     # 用矩形框设置裁剪区域

# 用QRegion设置裁剪区域
setClipRegion(arg_1:Union[QRegion, QBitmap, QPolygon, QRect], op:Qt.ClipOperation=Qt.ReplaceClip) -> None
clipRegion() -> QRegion                                                         # 获取裁剪区域

clipBoundingRect() -> QRectF                                                    # 获取裁剪区域的边界矩形

  其中参数 opQt.ClipOperation 类型的枚举值,可以取值如下:

Qt.ClipOperation.NoClip
Qt.ClipOperation.ReplaceClip                                                    # 替换裁剪区域
Qt.ClipOperation.IntersectClip                                                  # 与现有裁剪区域取交集

  QRegion 类专门用于 定义裁剪区域QWidgetrepaint() 方法可以接受 QRegion 参数,限制刷新的范围。用 QRegion 类创建裁剪区域实例的方法如下:

QRegion()
QRegion(bitmap:Union[QBitmap, str])
QRegion(pa:Union[QPolygon, Sequence[QPoint], QRect], fillRule:Qt.FillRule=Qt.OddEvenFill)
QRegion(r:QRect, t:QRegion.RegionType=QRegion.Rectangle)
QRegion(region:Union[QRegion, QBitmap, QPloygon, QRect])
QRegion(x:int, y:int, w:int, h:int, t:QRegion.RegionType=QRegion.Rectangle)

  其中 tQRegion.RegionType 类型的枚举值,可以取值如下:

QRegion.RegionType.Rectangle
QRegion.RegionType.Ellipse

  QRegion 类的常用方法如下:

boundingRect() -> QRect                                                         # 获取边界

contains(p:QPoint) -> bool                                                      # 获取是否包含指定的点
contains(r:QRect) -> bool                                                       # 获取是否包含矩形

isEmpty()  -> bool                                                              # 获取是否为空
isNull() -> bool                                                                # 获取是否无效

setRects(rect:QRect, num:int) -> None                                           # 设置多个矩形区域
rectCount() -> int                                                              # 获取矩形区域的数量

begin() -> QRect                                                                # 获取第一个非重合的矩形
cbegin() -> QRect                                                               # 获取第一个非重合的矩形
end() -> QRect                                                                  # 获取最后一个非重合的矩形
cend() -> QRect                                                                 # 获取最后一个非重合的矩形

intersects(r:Union[QRegion, QBitmap, QPolygon, QRect]) -> bool                  # 获取是否与区域相交  

intersected(r:Union[QRegion, QBitmap, QPolygon, QRect]) -> QRegion              # 获取相交的区域 
subtracted(r:Union[QRegion, QBitmap, QPolygon, QRect]) -> QRegion               # 获取减去区域后的区域
united(r:Union[QRegion, QBitmap, QPolygon, QRect]) -> QRegion                   # 获取合并后的区域
xored(r:Union[QRegion, QBitmap, QPolygon, QRect]) -> QRegion                    # 获取异或区域

translate(p:QPoint) -> None                                                     # 平移区域
translate(dx:int, dy:int) -> None                                               # 平移区域
translated(p:QPoint) -> QRegion                                                 # 获取平移后的区域
translated(dx:int, dy:int) -> QRegion                                           # 获取平移后的区域

swap(other:Union[QRegion, QBitmap, QPolygon, QRect]) -> None                    # 交换区域

  QRegion 可以进行交、减、并和异或运算,这些运算的示意图如下所示。

剪切区域的布尔运算

  用 setRects(rect:Sequence[QRect]) 方法可以 设置多个矩形区域,多个矩形之间不能相互交叉,处于同一层的矩形必须有相同的高度,而不能连在一起,多个矩形可以合并成一个矩形。多个矩形首先按 y 值以升序排列,其次按 x 值以升序排列。

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPaintEvent, QPixmap, QRegion
from PySide6.QtCore import QRect

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象

        pixmap = QPixmap("assets/images/1.jpg")                                 # 2.创建图像对象

        painter.setClipping(True)                                               # 3.设置是否启动裁剪区域

        # 4.裁剪区域
        rect1 = QRect(self.width() // 20, self.height() // 10, self.width() // 10 * 4, self.height() // 10 * 3)
        rect2 = QRect(self.width() // 20, self.height() // 10 * 5, self.width() // 10 * 4, self.height() // 10 * 3)
        rect3 = QRect(self.width() // 20 * 11, self.height() // 10, self.width() // 10 * 4, self.height() // 10 * 3)
        rect4 = QRect(self.width() // 20 * 11, self.height() // 10 * 5, self.width() // 10 * 4, self.height() // 10 * 3)

        region1 = QRegion(rect1)                                                # 4.矩形裁剪区域
        region2 = QRegion(rect2)
        region3 = QRegion(rect3, t=QRegion.RegionType.Ellipse)                  # 5.椭圆裁剪区域
        region4 = QRegion(rect4, t=QRegion.RegionType.Ellipse)

        region = region1.united(region2).united(region3).united(region4)        # 6.裁剪区域的布尔运算,并集运算

        painter.setClipRegion(region)                                           # 7.用QRegion设置裁剪区域
        painter.drawPixmap(self.rect(), pixmap)                                 # 8.绘制图像

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束

十一、图形合成

  图形合成 是指当绘制新图形时,绘图设备上已经存在旧图形,对新图形和旧图形进行处理的方法。图形合成是基于像素,将旧图形的颜色值和 Alpha 通道的值与新图形的颜色值和 Alpha 通道的值进行合成处理。图形合成的处理 使用 QPaintersetCompositionMode(mode:QPainter.CompositionMode) 方法设置,用 compositionMode() 方法 获取合成模式,其中参数 modeQPainter.CompositionMode 的类型枚举值,可以取值如下:

QPainter.CompositionMode.CompositionMode_Source
QPainter.CompositionMode.CompositionMode_SourceIn
QPainter.CompositionMode.CompositionMode_SourceOut
QPainter.CompositionMode.CompositionMode_SourceAtop
QPainter.CompositionMode.CompositionMode_SourceOver                             # 默认值

QPainter.CompositionMode.CompositionMode_Destination
QPainter.CompositionMode.CompositionMode_DestinationIn
QPainter.CompositionMode.CompositionMode_DestinationOut
QPainter.CompositionMode.CompositionMode_DestinationAtop
QPainter.CompositionMode.CompositionMode_DestinationOver

QPainter.CompositionMode.CompositionMode_Clear
QPainter.CompositionMode.CompositionMode_Xor

  修改 template.py 文件的内容。

import sys

from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPaintEvent, QPixmap

class MyWidget(QWidget):
    def __init__(self):
        super().__init__()                                                      # 1.调用父类Qwidget类的__init__()方法
        self.resize(800, 600)                                                   # 2.设置窗口对象大小

    def paintEvent(self, event:QPaintEvent):
        painter = QPainter(self)                                                # 1.创建绘图对象

        pixmap = QPixmap("assets/images/1.jpg")                                 # 2.创建图像对象

        painter.drawPixmap(self.rect(), pixmap)                                 # 3.绘制图像

        painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceAtop) # 4.设置图像的合成方式

        ico = QPixmap("assets/images/1.png")
        painter.drawPixmap(10, 10, ico)                                         # 5.绘制图标

if __name__ == "__main__":
    app = QApplication(sys.argv)                                                # 1.创建一个QApplication类的实例
    window = MyWidget()                                                         # 2.创建一个窗口
    window.show()                                                               # 3.展示窗口
    sys.exit(app.exec())                                                        # 4.进入程序的主循环并通过exit()函数确保主循环安全结束
posted @ 2025-01-22 18:57  星光映梦  阅读(187)  评论(0)    收藏  举报