一、QPainter绘图
绘图是指在绘图设备(窗口、控件、图像、打印机等)上将用户构思出的图形绘制出来,图形包括点、线、矩形、多边形、椭圆、文字及保存到磁盘上的图像等。可以对绘制的图形进行处理,如给封闭的图形填充颜色。
绘图设备是从 QPaintDevice 继承的类,包括继承自 QWidget 的窗口、各种控件、QPixmap 和 QImage。如果绘图设备是窗口或控件,则 QPainter 绘图一般放到 paintEvent()
事件或者被 paintEvent()
事件调用的函数中。
我们可以在终端中使用 pip 安装 pyside6 模块。
pip install pyside6
用 QPainter 类创建绘图实例的方法如下:
QPainter()
QPainter(device=QPaintDevice)
其中 QPaintDevice 是指继承自 QPaintDevice 的绘图设备。如果使用不带设备的 QPainter()
方法创建实例对象,,则在开始绘图前需要用 painter.begin(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,n Qt.GlobalColor, QColor, QGradient, QImage, QPixmap]) -> None # 设置画刷
setBrush(style:Qt.BrushStyle) -> None # 设置画刷
setBrushOrigin(arg__1: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 用于绘制线条,线条有样式(实线、虚线、点虚线)、颜色、宽度等属性,用 QPainter 的 setPen(QPen)
方法为 QPainter 设置钢笔。
用 QPen 创建钢笔的方法如下:
QPen()
QPen(s:Qt.PenStyle)
QPen(brush:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage, QPixmap], width:float, s:Qt.PenStyle=Qt.SolidLine, c:Qt.PenCapstyle=Qt.SquareCap, j:Qt.PenJoinstyle=Qt.BevelJoin)
QPen(color:Union[QColor, Qt.GlobalColor, str, int])
QPen(pen:Union[QPen, Qt.PenStyle, QColor])
其中 s 是 Qt.PenStyle 的枚举值,用于设置钢笔的样式;画刷 brush 可以用 QBrush、QColor、Qt.GlobalColor 和 QGradient 来设置;c 是 Qt.PenCapStyle 的枚举值,用于设置线条端点样式;j 是 Qt.PenJoinStyle 的枚举值,用于设置线条连接点处的样式。钢笔默认的颜色是黑色,宽度是 1 像素,样式是实线,端点样式是 Qt.SquareCap,连接处是 Qt.BevelJoin。
QPen 类的常用方法如下:
setStyle(arg__1: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(pcs: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(pcs:Qt.PenJoinStyle) -> None # 设置两相交线连接点出的样式
setMiterLimit(limit:float) -> None # 设置斜接延长线的长度
线条的宽度用 setWidth(int)
或 setWidthF(float)
方法设置,如果宽度始终为 0,表示是装饰线条;装饰线条也可用 setCosmetic(bool)
方法设置。装饰线条是指具有恒定宽度的边,可确保线条在不同缩放比例下具有相同的宽度。
线条的样式用 setStyle(Qt.PenStyle)
方法设置,参数 Qt.PenStyle 可取的值如下所示。
Qt.PenStyle.NoPen # 不绘制线条
Qt.PenStyle.SolidLine # 实线
Qt.PenStyle.DashLine # 虚线
Qt.PenStyle.DotLine # 点线
Qt.PenStyle.DashDotLine # 点画线
Qt.PenStyle.DashDotDotLine # 双点划线
Qt.PenStyle.CustomDashLine # 自定义线
钢笔的端点样式用 setCapStyle(Qt.PenCapStyle)
方法设置,其中参数 Qt.PenCapStyle 可取值如下:
Qt.PenCapStyle.FlatCap # 不包含端点
Qt.PenCapStyle.SquareCap # 包含端点
Qt.PenCapStyle.RoundCap # 包含端点,并延长半个宽度
两个线条连接点处的样式用 setJoinStyle(Qt.PenJoinStyle)
方法设置,其中参数 Qt.PenJoinStyle 可取值如下:
Qt.PenJoinStyle.MiterJoin
Qt.PenJoinStyle.BevelJoin
Qt.PenJoinStyle.RoundJoin
Qt.PenJoinStyle.SvgMiterJoin
线条连接样式是 Qt.MiterJoin 时,用 setMiterLimit(float)
方法设置延长线的长度,其中参数 float 是线条宽度的倍数,默认是2.0,其延长线的含义如下所示。
用 setDashPattern(Sequence[float])
方法可以自定义虚线样式,其中参数的奇数项表示实线的长度,偶数项表示空白处的长度,长度以线宽为单位,表示为线宽的倍数。
用 setDashOffset(float)
方法可以设置虚线开始绘制的点与线起始点之间的距离,如果这个距离是动态的,则会形成动画效果。
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPen
from PySide6.QtCore import Qt, QPointFclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2、创建画笔对象pen = QPen()# 3、设置线条颜色pen.setColor(Qt.GlobalColor.blue)# 4、设置线条的宽度pen.setWidth(10)# 5、设置线条样式pen.setStyle(Qt.PenStyle.DashDotDotLine)# 6、设置线条的端点样式pen.setCapStyle(Qt.PenCapStyle.RoundCap)# 7、设置两个线条连接点处的样式pen.setJoinStyle(Qt.PenJoinStyle.RoundJoin)# 8、设置画笔painter.setPen(pen)# 0、绘制一条折线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])if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
三、设置画刷
对于封闭的图形,如矩形、圆等,用画刷 QBrush 可以在其内部填充颜色、样式、渐变、纹理或图案。
用 QBrush 类创建画刷的方法如下所示。
QBrush()
QBrush(brush:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage, QPixmap])
QBrush(bs:Qt.BrushStyle)
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(arg__1: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(arg__1:QTransform) -> None # 设置变换矩阵
transform() -> QTransform # 获取变换矩阵
isOpaque() -> bool # 设置是否不透明
画刷的风格用 setStyle(Qt.BrushStyle)
方法设置,其中参数 Qt.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(QPixmap)
或 setTextureImage(QImage)
方法来设置,这时样式被设置成 Qt.TexturePattern。
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QBrush
from PySide6.QtCore import Qt, QPointF, QRectFclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2、创建画刷对象brush = QBrush()# 3、设置画刷颜色brush.setColor(Qt.GlobalColor.blue)# 4、设置画刷样式brush.setStyle(Qt.BrushStyle.CrossPattern)# 5、设置画刷painter.setBrush(brush)# 6、绘制一个矩形p1 = QPointF(self.width() / 4, self.height() / 4)p2 = QPointF(3 * self.width() / 4, 3 * self.height() / 4)painter.drawRect(QRectF(p1, p2))if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
四、渐变色
在用画刷进行填充时,可以设置填充颜色为渐变色。所谓渐变色是指在两个不重合的点处分别设置不同的颜色,这两个点一个是起点,另一个是终点,这两个点之间的颜色从起点的颜色逐渐过渡到终点的颜色。
定义渐变色的类是 QGradient,渐变样式分为 3 种类型,分别为 线性渐变 QLinearGradient、径向渐变 QRadialGradient 和 圆锥渐变 QConicalGradient,它们都继承自 QGradient 类,也会继承 QGradient 类的属性和方法。
用 QLinearGradient 类创建线性渐变色的方法如下所示。线性渐变需要一个线性渐变矩形区域(起始和终止位置),参数用于确定这个矩形区域。
QLinearGradient()
QLinearGradient(start:Union[QPointF, QPoint, QPainterPath.Element], finalStop:Union[QPointF, QPainterPath.Element])
QLinearGradient(xStart:float, yStart:float, xFinalStop:float, yFinalStop:float)
用 QRadialGradient 类创建径向渐变色的方法如下。径向渐变需要的几何参数下所示,需要确定圆心位置、半径、焦点位置和焦点半径。径向渐变的构造函数中,第 1 个参数是圆心位置,可以用点或坐标定义;第 2 个参数是半径;第 3 个参数是焦点位置,可以用点或坐标定义;第 4 个参数是焦点半径。如果焦点设置到圆的外面,则取圆上的点作为焦点。
QRadialGradient()
QRadialGradient(center:Union[QPointF, QPoint, QPainterPath.Element], centerRadius:float, focalPoint:Union[QPointF, QPoint, QPainterPath.Element], focalRadius:float)
QRadialGradient(center:Union[QPointF, QPoint, QPainterPath.Element], radius: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(cx:float, cy:float, radius:float)
QRadialGradient(cx:float, cy:float, radius:float, fx:float, fy:float)
用 QConicalGradient 创建圆锥渐变色的方法如下所示。圆锥渐变需要的几何参数为圆心位置和起始角度 a,角度必须在 0°~360° 之间,圆心位置可以用点或坐标来定义。
QConicalGradient()
QConicalGradient(center:Union[QPointF, QPoint, QPainterPath.Element], startAngle:float)
QConicalGradient(cx:float, cy:float, startAngle:float)
QLinearGradient、QRadialGradient 和 QConicalGradient 继承自 QGradient,因此也会继承 QGradient 的方法。QGradient 类的常用方法如下:
setCoordinateMode(mode:QGradient.CoordinateMode) -> None # 设置坐标模式
setColorAt(pos:float, color:Union[QColor, Qt.GlobalColor, str]) -> None # 设置颜色
setStops(stops:Sequence[Tuple[float, QColor]]) -> None # 设置颜色
setInterpolationMode(mode:QGradient.InterpolationMode) -> None # 设置插值模式
setSpread(spread:QGradient.Spread) -> None # 设置扩展模式
type() -> QGradient.Type # 获取类型
在渐变区域内,可以在多个点设置颜色值,这些点之间的颜色值根据两侧的颜色来确定。在定义内部点的颜色值时,通常通过逻辑坐标来定义,渐变区域内的起始点的逻辑值是 0,终止点的逻辑值是 1。如果要在中间位置定义颜色,可以用 setColorAt()
方法来定义。我们也可以用 setStops()
方法一次定义多个颜色值。
用 setCoordinateMode(QGradient.CoordinateMode)
方法可以设置坐标的模式,参数 QGradient.CoordinateMode 的取值如下所示。
QGradient.CoordinateMode.LogicalMode # 逻辑方式,起始点为0,终止点为1,这是默认值
QGradient.CoordinateMode.ObjectMode # 相对于绘图区域矩形边界的逻辑坐标,左上角的坐标是(0, 0),右下角的坐标是(1, 1)
QGradient.CoordinateMode.StretchToDeviceMode # 相对于绘图设备矩形边界的逻辑坐标,左上角的坐标是(0, 0),右下角的坐标是(1, 1)
QGradient.CoordinateMode.ObjectBoundingMode # 与ObjectMode基本相同,除了QBrush.transform()应用与逻辑空间而不是物理空间
当设置的渐变区域小于填充区域时,渐变颜色可以扩展到渐变区域以外的空间。扩展模式用 setSpread(QGradient.Spread)
方法定义,参数 QGradient.Spread 的取值如下所示。扩展模式不适合圆锥渐变,圆锥渐变没有固定的边界。
QGradient.Spread.PadSpread # 用最近的颜色扩展
QGradient.Spread.RepeatSpread # 重复渐变
QGradient.Spread.ReflectSpread # 对称渐变
用 setInterpolationMode(mode:QGradient.InterpolationMode)
方法设置渐变色内部的插值模式,参数可取值如下:
QGradient.InterpolationMode.ColorInterpolation
QGradient.InterpolationMode.ComponentInterpolation
用 type()
方法可以获取渐变类型,返回值可能如下:
QGradient.Type.LinearGradient
QGradient.Type.RadialGradient
QGradient.Type.ConicalGradient
QGradient.Type.NoGradient # 无渐变色
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 # 获取终止点
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 # 设置焦点半径
QConicalGradient 类的常用方法:
setCenter(center:Union[QPointF, QPoint]) -> None # 设置圆心
setCenter(x:float, y:float) -> None # 设置圆心
setAngle(angle:float) -> None # 设置起始角度
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPen, QBrush
from PySide6.QtGui import QLinearGradient, QRadialGradient, QConicalGradient
from PySide6.QtCore import Qt, QPointF, QRectFclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):w = self.width()h = self.height()# 1、创建绘图对象painter = QPainter(self)# 2.1、创建钢笔对象,绘制边框pen = QPen()# 2.2、设置边框宽度pen.setWidth(5)# 2.3、设置边框颜色pen.setColor(Qt.GlobalColor.darkBlue)# 2.4、设置边框样式pen.setStyle(Qt.PenStyle.DashLine)# 2.5、设置钢笔painter.setPen(pen)# 3.1、线性渐变linear = QLinearGradient(QPointF(0, 0), QPointF(w / 8, 0))# 3.2、设置颜色linear.setStops([(0, Qt.GlobalColor.red), (0.3, Qt.GlobalColor.yellow), (0.6, Qt.GlobalColor.green), (1, Qt.GlobalColor.blue)])# 3.3、设置扩展模式linear.setSpread(QLinearGradient.Spread.ReflectSpread)# 3.4、用线性渐变定义画刷brush = QBrush(linear)# 3,5、设置画刷painter.setBrush(brush)# 3.6、绘制矩形painter.drawRect(QRectF(0, 0, w / 2, h / 2))# 4.1、镜像渐变radial = QRadialGradient(QPointF(w / 4 * 3, h / 4), w / 8, QPointF(w / 4 * 3, h / 4), w / 15)# 4.2、设置颜色radial.setColorAt(0, Qt.GlobalColor.red)radial.setColorAt(0.5, Qt.GlobalColor.yellow)radial.setColorAt(1, Qt.GlobalColor.blue)# 4.3、设置扩展模式radial.setSpread(QRadialGradient.Spread.RepeatSpread)# 4.4、用镜像渐变创建画刷brush = QBrush(radial)# 4.5、设置画刷painter.setBrush(brush)# 4.6、绘制矩形painter.drawRect(QRectF(w / 2, 0, w / 2, h / 2))# 5.1、圆锥渐变conical = QConicalGradient(QPointF(w / 4, h / 4 * 3), h / 6)# 5.2、设置开始角度conical.setAngle(60)# 5.3、设置颜色conical.setColorAt(0, Qt.GlobalColor.red)conical.setColorAt(1, Qt.GlobalColor.yellow)# 5.4、以圆锥渐变创建画刷brush = QBrush(conical)# 5.5、设置画刷painter.setBrush(brush)# 5.6、绘制矩形painter.drawRect(QRectF(0, h / 2, w / 2, h / 2))# 6.1、镜像渐变radial = QRadialGradient(QPointF(w / 4 * 3, h / 4 * 3), w / 6, QPointF(w / 5 * 4, h / 5 * 4), w / 10)# 6.2、设置颜色radial.setColorAt(0, Qt.GlobalColor.red)radial.setColorAt(0.5, Qt.GlobalColor.yellow)radial.setColorAt(1, Qt.GlobalColor.blue)# 6.3、设置扩展模式radial.setSpread(QRadialGradient.Spread.ReflectSpread)# 6.4、用镜像渐变创建画刷brush = QBrush(radial)# 6.5、设置画刷painter.setBrush(brush)# 6.6、绘制矩形painter.drawRect(QRectF(w / 2, h / 2, w / 2, h / 2))if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
五、绘制几何图形
QPainter 可以在绘图设备上绘制点、直线、折线、矩形、椭圆、弧、弦、文本和图像等。
5.1、绘制点
QPainter 可以一次绘制一个点,也可以一次绘制多个点,其中 QPolygon 和 QPolygonF 是用于存储多个 QPoint 和 QPointF 的类。
# 绘制单点
drawPoint(x:int, y:int) -> None
drawPoint(p:QPoint) -> None
drawPoint(pt:Union[QPointF, QPoint]) -> None
drawPoint(pt:QPainterPath.Element) -> None# 绘制多点
drawPoints(arg__1:Sequence[QPointF]) -> None
drawPoints(arg__1:Sequence[QPoint]) -> None
drawPoints(points:Union[QPolygon, Sequence[QPoint], QRect])
drawPoints(points:Union[QPolygon, Sequence[QPoint], QPolygon, QRectF])
创建 QPolygon 实例的方法如下:
QPolygon()
QPolygon(arg_1:Sequence[QPoint])
创建 QPolygonF 实例的方法如下:
QPolygonF()
QPolygonF(arg_1:Sequence[Union[QPointF,QPoint]])
用 QPolygon 的 append(QPoint)
方法可以添加点,用 insert(int,QPoint)
方法可以插入点,用 setPoint(int,QPoint)
方法可以更改点;用 QPolygonF 的 append(Union[QPointF,QPoint])
方法可以添加点,用 insert(int,Union[QPointF,QPoint])
方法可以插入点。
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPen, QBrush
from PySide6.QtCore import QPointclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2.1、创建钢笔对象pen = QPen()# 2.2、设置钢笔的颜色pen.setColor("red")# 2.3、设置钢笔的宽度pen.setWidth(10)# 2.4、使用钢笔对象painter.setPen(pen)# 3、绘制点painter.drawPoint(QPoint(self.width() // 2, self.height() // 2))if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
5.2、绘制直线
绘制直线需要用两个点。可以一次绘制一条直线,也可一次绘制多条直线,其中 QLine 或 QLineF 是 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)
用 QLine 的 setLine(x1:int,y1:int,x2:int,y2:int)
方法、setP1(QPoint)
方法、setP2(QPoint)
或 setPoints(QPoint,QPoint)
方法可以设置线两端的点。QLineF 也有同样的方法,只需把参数 int 改成 float,或 QPoint 改成 QPointF。
在绘制几何图像和文字时,如果线条是斜线,对线条进行放大后会发现它呈现锯齿状。为防止出现锯齿状,需要对线条边缘进行模糊化处理。用 QPainter 的 setRenderHint(hint:QPainter.RenderHint,on:bool=True)
或 setRenderHints(hints:QPainter.RenderHints,on:bool=True)
方法可以设置是否进行抗锯齿处理,用 testRenderHint(hint:QPainter.RenderHint)
方法可以获取是否设置了抗锯齿算法,其中枚举参数 QPainter.RenderHint 可以取值如下:
QPainter.RenderHint.Antialiasing # 启用抗锯齿
QPainter.RenderHint.TextAntialiasing # 对文本进行抗锯齿
QPainter.RenderHint.SmoothPixmapTransform # 使用平滑的像素图像算法
QPainter.RenderHint.LosslessImageRendering # 用于PDF文档
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter
from PySide6.QtCore import QPointclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2、绘制直线painter.drawLine(QPoint(0, 0), QPoint(self.width(), self.height()))# 3.抗锯齿painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
5.3、绘制折线
绘制折线必须用两个点,即使两条折线的终点和起始点相同,每条折线也必须用两个点来定义。折线由多个折线段构成,绘制折线需要给出多个点,上个折线段的终点是下个折线段的起始点。
drawPolyline(arg__1:Sequence[QPoint]) -> None
drawPolyline(arg__1:Sequence[QPointF]) -> None
drawPolyline(polygon:Union[QPolygon, Sequence[QPoint], QRect]) -> None
drawPolyline(polygon:Union[QPolygonF, Sequence[QPointF], QRectF]) -> None
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter
from PySide6.QtCore import QPointclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)p1 = QPoint(10, 10)p2 = QPoint(self.width() - 10, 10)p3 = QPoint(10, self.height() - 10)p4 = QPoint(self.width() - 10, self.height() - 10)# 2、绘制折线painter.drawPolyline([p1, p2, p3, p4])if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
5.4、绘制矩形
QPainter 可以一次绘制一个矩形,也可以一次绘制多个矩形。
# 绘制单个矩形
drawRect(rect:QRect) -> None
drawRect(rect:Union[QRect, QRectF]) -> None
drawRect(x1:int, y1:int, w:int, h:int) -> None# 绘制多个矩形
drawRects(rectangles:Sequence[QRect]) -> None
drawRects(rectangles:Sequencep[QRectF]) -> None
其中 drawRect(x1:int,y1:int,w:int,h:int)
方法中 x1 和 y1 参数确定左上角的位置,w 和 h 参数确定宽度和高度。
圆角矩形是在矩形的基础上对 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
其中参数 mode 是 Qt.SizeMode 的枚举类型,可以取值如下:
Qt.SizeMode.AbsoluteSize # 椭圆半径是绝对值
Qt.SizeMode.RelativeSize # 椭圆半径是相对于矩形边长的相对值
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter
from PySide6.QtCore import QRect, Qtclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2.设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2、绘制矩形painter.drawRect(QRect(10, 10, self.width() - 20, self.height() // 2 - 20))# 3、绘制圆角矩形painter.drawRoundedRect(QRect(10, self.height() // 2, self.width() - 20, self.height() // 2 - 20), 50, 30, Qt.SizeMode.AbsoluteSize)if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
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
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter
from PySide6.QtCore import QRectclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2、绘制椭圆painter.drawEllipse(QRect(10, 10, self.width() // 2 - 20, self.height() // 2 - 20))# 3.绘制扇形painter.drawPie(QRect(self.width() // 2, self.height() // 2, self.width() // 2 - 20, self.height() // 2 - 20), 45 * 16, 60* 16)if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
5.6、绘制多边形
QPainter 绘制多边形和凸多边形的方法如下所示。
# 绘制多边形
drawPolygon(arg__1:Sequence[QPoint], arg__2:Qt.FillRule) -> None
drawPolygon(arg__1:Sequence[QPointF], arg__2:Qt.FillRule) -> None
drawPolygon(polygon:Union[QPolygon, Sequence[QPoint], QRect], fillRule:Qt.FillRule=Qt.OddEvenFill) -> None
drawPolygon(polygon:Union[QPolygonF, Sequence[QPointF], QPolygon, QRectF], fillRule:Qt.FillRule=Qt.OddEvenFill) -> None# 绘制凸多边形
drawConvexPolygon(polygon:Union[QPolygon, Sequence[QPoint], QRect]) -> None
drawConvexPolygon(polygon:Union[QPolygonF, Sequence[QPointF], QPolygon, QRectF]) -> None
使用这些方法时,需要给出多边形或凸多边形的顶点,系统会自动在起始点和终止点之间建立直线,使多边形封闭。参数 fillRule 是 Qt.FillRule 的枚举类型,用于确定一个点是否在图形内部,在内部的区域可以进行填充。fillRule 可以取值如下:
Qt.FillRule.OddEvenFill
Qt.FillRule.WindingFill
Qt.FillRule.OddEvenFill 是奇偶填充规则,要判断一个点是否在图形中,可以从该点向图形外引一条水平线,如果该水平线与图形的交点个数为奇数,那么该点在图形中。Qt.FillRule.WindingFill 是非零绕组填充规则,要判断一个点是否在图形中,可以从该点向图形外引一条水平线,如果该水平线与图形的边线相交,这个边线是顺时针绘制的,就记为 1,是逆时针绘制的就记为 -1,然后将所有数值相加,若结果不为 0,那么该点就在图形中。
import sysfrom math import sin, cos, pi
from PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPen, QBrush
from PySide6.QtCore import QRect, Qt, QPointFclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2、设置钢笔pen = QPen()pen.setWidth(2)painter.setPen(pen)# 3、设置画刷brush = QBrush(Qt.BrushStyle.SolidPattern)painter.setBrush(brush)r = 100x = self.width() / 4y = self.height() / 4p1 = QPointF(r * cos(-90 * pi / 180) + x, r * sin(-90 * pi / 180) +y)p2 = QPointF(r * cos(-18 * pi / 180) + x, r * sin(-18 * pi / 180) +y)p3 = QPointF(r * cos(54 * pi / 180) + x, r * sin(54 * pi / 180) +y)p4 = QPointF(r * cos(126 * pi / 180) + x, r * sin(126 * pi / 180) +y)p5 = QPointF(r * cos(198 * pi / 180) + x, r * sin(198 * pi / 180) +y)# 4、绘制多边形painter.drawPolygon([p1, p2, p3, p4, p5], Qt.FillRule.OddEvenFill)offset = QPointF(self.width() / 2, 0)painter.drawConvexPolygon([p1 + offset, p2 + offset, p3 + offset, p4 + offset, p5 + offset])if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
六、绘制文本
可以在指定位置绘制文本,绘制文本时,通常需要先用 setFont(QFont)
方法设置 QPainter 的字体。绘制文本的方法如下所示,所绘文本默认是反锯齿的。
drawStaticText(topLeftPosition:Union[QPoint, QPointF, QPainterPath.Element], staticText:QStaticText) -> None
drawStaticText(left:int, top:int, staticText:QStaticText) -> NonedrawText(p:Union[QPoint, QPointF, QPainterPath.Element], s:str) -> None
drawText(p:QPoint, s:str) -> None
drawText(r:Union[QRect, QRectF], flags:int, text:str) -> None
drawText(x:int, y:int, s:str) -> None
drawText(x:int, y:int, w:int, h:int, flags:int, text:str) -> None
绘制文本可以用 drawStaticText()
方法,该方法比较快,且每次不用重新计算文本的排列位置。QStaticText 是静态文本类,用 QStaticText 类创建静态文本的方法是 QStaticText()
或 QStaticText(str)
。可以用 QStatciText 的 setText(str)
方法设置文本;用 setTextFormat(Qt.TextFormat)
方法设置静态文本的格式,参数 Qt.TextFormat 可取值如下:
Qt.TextFormat.PlainText
Qt.TextFormat.RichText
Qt.TextFormat.AutoText
Qt.TextFormat.MarkdownText
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainterclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2.绘制文本painter.drawText(10, 100, "你好,世界!")if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
七、绘图路径
为了将简单的图形组合成复杂且封闭的图形,需要用到绘图路径 QPainterPath,前面介绍的绘图方法所绘制的图形都可以加入 QPainterPath 中,构成 QPainterPath 的元素。用 QPainter 的 drawPath(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(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) -> NoneaddRegion(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 # 由当前路径的终点位置与给定路径的起始位置绘制直线
路径是由多个图形构成的,每个图形中可能包括直线、贝塞尔曲线、弧、椭圆、多边形、矩形或文本。使用 moveTo()
方法把当前路径移到指定位置,作为绘图开始的起点位置,移动当前点会启用一个新的子路径,并自动封闭之前的路径。
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 # 如果包含指定的路径,则返回TruecontrolPointRect() -> 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] # 将每个元素转换成QPolygonFtranslated(offset:Union[QPoint, QPointF]) -> QPainterPath # 获取平移后的绘图路径
translated(dx:float, dy:float) -> QPainterPath # 获取平移后的绘图路径
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainterPath, QPainter, QPen, QBrush, Qt
from PySide6.QtCore import QPointFclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建路径path = QPainterPath()center = QPointF(self.width() / 2, self.height() / 2)r = min(self.width() , self.height()) / 3# 2、将当前点移动到指定点,作为起始点path.moveTo(center)# 3、绘制圆弧path.arcTo(center.x() - r, center.y() - r, 2 * r, 2 * r, 0, 360)# 4、设置填充方式path.setFillRule(Qt.FillRule.WindingFill)# 5、创建绘画对象painter = QPainter(self)# 6、创建钢笔对象pen = QPen()pen.setWidth(5)pen.setColor(Qt.GlobalColor.black)# 7、使用钢笔对象painter.setPen(pen)# 8、创建画刷对象brush = QBrush(Qt.BrushStyle.SolidPattern)# 9、使用画刷对象painter.setBrush(brush)# 10、绘制路径painter.drawPath(path)super().paintEvent(event)if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
八、填充
用 QPainter 绘图时,如果所绘制的图形是封闭的,且为 QPainter 设置了画刷,则系统自动在封闭的图形内填充画刷的图案,封闭的图形包括绘图路径、矩形、椭圆、多边形。除此之外,还可以为指定的矩形范围填充图案,此时不需要有封闭的边界线。
QPainter 类的用来填充的常用方法如下:
# 为指定的路径填充颜色
fillPath(path:QPainterPath, brush:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, QGradient, QImage, QPixmap]) -> None# 用画刷填充指定的矩形区域
fillPath(path:Union[QRect, QRectF], brush:Union[QBrush, Qt.BrushStyle, Qt.GlobalColor, QColor, str, QGradient, QImage, QPixmap]) -> None
# 用颜色和渐变色填充指定的矩形区域
fillRect(x:int, y:int, w:int, h: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, w:int, h:int) -> NonesetBackground(bg:Union[QBrush, QColor, Qt.GlobalColor, QGradient]) -> None # 设置背景色
background() -> QBrush # 获取背景画刷
setBackgroundMode(mode:Qt.BGMode) -> None # 设置背景模式
setBrushOrigin(arg__1:Union[QPoint, QPointF, QPainterPath.Element]) -> None # 设置画刷的起始点
setBrushOrigin(x:int, y:int) -> None # 设置画刷的起始点
brushOrigin() -> None # 获取起始点QPoint
用 fillRect()
方法可以给指定的矩形区域绘制填充颜色,这时无须封闭的空间,也不会绘制出轮廓;用 eraseRect()
方法可以擦除矩形区域的填充。
用 setBackgroundMode(Qt.BGMode)
方法设置背景的模式,其中参数 Qt.BGMode 可以取值如下:
Qt.BGMode.TransparentMode # 透明模式
Qt.BGMode.OpaqueMode # 不透明模式
用 setBackground(Union[QBrush,QColor,Qt.GlobalColor,QGradient])
方法设置背景色,背景色只有在不透明模式下才起作用。
用 setBrushOrigin(Union[QPointF,QPoint])
、setBrushOrigin(int,int)
或 setBrushOrigin(QPoint)
方法设置画刷的起始点,起始点会影响纹理、渐变色的布局。
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter
from PySide6.QtGui import QLinearGradient, QPen, QBrush
from PySide6.QtCore import QPointF, Qtclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2.1、使用线性渐变充当文字颜色linear_1 = QLinearGradient(QPointF(0, 0), QPointF(self.width(), self.height()))# 2.2、设置颜色linear_1.setStops([(0, Qt.GlobalColor.red), (0.3, Qt.GlobalColor.yellow), (0.6, Qt.GlobalColor.green), (1, Qt.GlobalColor.blue)])# 2.3、设置扩展模式linear_1.setSpread(QLinearGradient.Spread.ReflectSpread)# 2.4、用线性渐变定义画刷brush_1 = QBrush(linear_1)# 3、创建钢笔对象pen = QPen()pen.setBrush(brush_1)painter.setPen(pen)# 4、创建字体对象font = painter.font()font.setFamily("楷体")font.setBold(True)font.setPointSize(50)# 5、使用字体对象painter.setFont(font)# 6、设置背景模式不透明painter.setBackgroundMode(Qt.BGMode.OpaqueMode)# 7.1、使用线性渐变充当文字颜色linear_2 = QLinearGradient(QPointF(0, 0), QPointF(self.width(), self.height()))# 7.2、设置颜色linear_2.setStops([(0, Qt.GlobalColor.blue), (0.3, Qt.GlobalColor.green), (0.6, Qt.GlobalColor.red), (1, Qt.GlobalColor.white)])# 7.3、设置扩展模式linear_2.setSpread(QLinearGradient.Spread.ReflectSpread)# 7.4、用线性渐变定义画刷brush_2 = QBrush(linear_2)# 8、设置背景画刷painter.setBackground(brush_2)# 9、设置画刷的起始点painter.setBrushOrigin(0, 0)# 10、绘制字体painter.drawText(100, 100, "你好,世界!")if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
九、绘制图像
QPainter 还可以把 QPixmap、QImage 和 QPicture 图像直接绘制在绘图设备上。
绘制 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(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
drawTiledPixmap(x:int, y:int, w:int, h:int, pm:Union[QPixmap, QImage, str], sx:int=0, sy:int=0) -> 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.OpaqueHint;参数 QPainter.PixmapFragment 的创建方法如下:
QPainter.PixmapFragment.create(pos:QPointF,sourceRect:QRectF,scaleX=1,scaleY=1,rotation=0,opacity=1)
其中 pos 是图像绘制地点,sourceRect 是截取的图像的部分区域,scaleX 和 scaleY 是缩放比例,rotation 是旋转角度,opacity 是不透明度值。
绘制 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
对于 QPicture 图像,只能在绘图设备的指定点上按照原始尺寸进行绘制。绘制 QPicture 图像的方法如下:
drawPicture(p:Union[QPointF, QPoint, QPainterPath.Element], picture:Union[QPicture,int]) -> None
drawPicture(x:int, y:int, picture:Union[QPicture,int]) -> None
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPixmapclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2、创建图像对象pixmap = QPixmap("./1.jpg")# 3、绘制图像painter.drawPixmap(self.rect(), pixmap)if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
十、裁剪区域
当所绘图形比较大时,若只想显示绘图上的一部分区域的内容,其他区域的内容不显示,就需要使用裁剪区域。用 QPainter 设置裁剪区域的方法下所示:
setClipping(enable:bool) -> None # 设置是否启动裁剪区域
hasClipping() -> bool # 获取是否有裁剪区域
setClipPath(path:QPainterPath, op:Qt.ClipOperation=Qt.ReplaceClip) -> None # 用路径设置裁剪区域
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 # 用矩形框设置裁剪区域
setClipRegion(arg_1:Union[QRegion, QBitmap, QPolygon, QRect], op:Qt.ClipOperation=Qt.ReplaceClip) -> None # 用QRegion设置裁剪区域
clipBoundingRect() -> QRectF # 获取裁剪区域的边界矩形
clipPath() -> QPainterPath # 获取裁剪区域的路径
clipRegion() -> QRegion # 获取裁剪区域
其中参数 op 是 Qt.ClipOperation 的枚举值,可以取值如下:
Qt.ClipOperation.NoClip
Qt.ClipOperation.ReplaceClip # 替换裁剪区域
Qt.ClipOperation.IntersectClip # 与现有裁剪区域取交集
QRegion 类专门用于定义裁剪区域,QWidget 的 repaint() 方法可以接受 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)
其中 t 是 QRegion.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(Sequence[QRect])
方法可以设置多个矩形区域,多个矩形之间不能相互交叉,处于同一层的矩形必须有相同的高度,而不能连在一起,多个矩形可以合并成一个矩形。多个矩形首先按 y 值以升序排列,其次按 x 值以升序排列。
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPixmap, QRegion
from PySide6.QtCore import QRectclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2、创建图像对象pixmap = QPixmap("./1.jpg")# 3、设置是否启动裁剪区域painter.setClipping(True)# 4、裁剪区域rect_1 = QRect(self.width() // 20, self.height() // 10, self.width() // 10 * 4, self.height() // 10 * 3)rect_2 = QRect(self.width() // 20, self.height() // 10 * 5, self.width() // 10 * 4, self.height() // 10 * 3)rect_3 = QRect(self.width() // 20 * 11, self.height() // 10, self.width() // 10 * 4, self.height() // 10 * 3)rect_4 = QRect(self.width() // 20 * 11, self.height() // 10 * 5, self.width() // 10 * 4, self.height() // 10 * 3)region_1 = QRegion(rect_1) # 矩形裁剪区域region_2 = QRegion(rect_2) # 矩形裁剪区域region_3 = QRegion(rect_3, t=QRegion.RegionType.Ellipse) # 椭圆裁剪区域region_4 = QRegion(rect_4, t=QRegion.RegionType.Ellipse) # 椭圆裁剪区域# 5、裁剪区域的布尔运算,并集运算region = region_1.united(region_2).united(region_3).united(region_4)# 6、用QRegion设置裁剪区域painter.setClipRegion(region)# 7、绘制图像painter.drawPixmap(self.rect(), pixmap)if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())
十一、图形合成
图形合成是指当绘制新图形时,绘图设备上已经存在旧图形,对新图形和旧图形进行处理的方法。图形合成是基于像素,将旧图形的颜色值和 Alpha 通道的值与新图形的颜色值和 Alpha 通道的值进行合成处理。图形合成的处理使用 QPainter 的 setCompositionMode(mode:QPainter.CompositionMode)
方法设置,用 compositionMode()
方法获取合成模式,其中参数 mode 是 QPainter.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_DestinationOverQPainter.CompositionMode.CompositionMode_Clear
QPainter.CompositionMode.CompositionMode_Xor
import sysfrom PySide6.QtWidgets import QApplication, QWidget
from PySide6.QtGui import QPainter, QPixmap
from PySide6.QtCore import QRectFclass MyWidget(QWidget):def __init__(self):# 1、调用父类的__init__()方法super().__init__()# 2、设置窗口对象大小self.resize(700, 500)def paintEvent(self, event):# 1、创建绘图对象painter = QPainter(self)# 2、创建图像对象pixmap = QPixmap("./1.jpg")# 3、绘制图像painter.drawPixmap(self.rect(), pixmap)# 4、设置图像的合成方式painter.setCompositionMode(QPainter.CompositionMode.CompositionMode_SourceAtop)# 5、获取窗口的取行rect = QRectF(0, 0, self.width(), self.height())# 6.绘制图标ico = QPixmap("./1.ico")painter.drawPixmap(10, 10, ico)if __name__ == "__main__":# 1、创建一个QApplication类的实例app = QApplication(sys.argv)# 2、创建一个窗口window = MyWidget()# 3、展示窗口window.show()# 4、进入程序的主循环并通过exit()函数确保主循环安全结束sys.exit(app.exec())