绘图路径QPainterPath的用法
前文中绘制的几何图形比较简单,各个图形之间也是相互独立的,例如用line()或 lines()方法绘制的多个线条之间相互独立,即便是首尾相连,它们也不是封闭的,不能在其内部填充图案。
为了将简单的图形组合成复杂且封闭的图形,需要用到绘图路径 QPainterPath,前面介绍的绘图方法所绘制的图形都可以加入QPainterPath 中,构成QPainterPath的元素。
用QPainter 的drawPath(path; QPainterPath)方法或strokePath(path:QPainterPath,pen;Union[QPen,Qt.PenStyle,QColor])方法可以将绘图路径的图形绘制出来
用绘图路径绘制的图形不论是否封闭,都隐含是封闭的,可以在其内部进行填充QPainterPath是一些绘图命令按照先后顺序的有序组合创建一次后可以反复使用用QPainterPath类
创建绘图路径实例对象的方法如下所示其中startPoint是绘制路径的起始点,也可以用绘图路径的 moveTo(Union[QPointF,QPoint])或 moveTo(x:float;y:float)方法将绘图路径的当前点移到起始点
from PySide6.QtGui import QPainterPath
QPainterPath(self)-> None
QPainterPath(Other: PySide6.QtGui.QPainterPath)-> None
QPainterPath(startPoint: Union[PySide6.QtCore.QPointF,PySide6.QtCore.QPoint,PySide6.QtGui.QPainterPath.Element])-> None
绘图路径中与绘图有关的方法
QPainterPath的绘图方法及参数类型 | 说 明 |
---|---|
moveTo(Union[QPointF,QPoint]) | 将当前点移动到指定的点,作为下一个绘图单元的 起始点 |
moveTo(x:float,y:float) | 将当前点移动到指定的点,作为下一个绘图单元的 起始点 |
currentPosition() | 获取当前的起始点 QPointF |
arcMoveTo(rect: Union[QRectF,QRect],angle: float) | 将当前点移动到指定矩形框内的椭圆上,最后的 float是起始角度 |
arcMoveTo(x: float,y: float,w: float,h: float,angle: float) | 将当前点移动到指定矩形框内的椭圆上,最后的 float是起始角度 |
lineTo(Union[QPointF,QPoint,QPainterPath.Element]) | 在当前点与指定点之间绘制直线 |
lineTo(x: float,y: float) | 在当前点与指定点之间绘制直线 |
cubicTo(ctrlPt1: Union[QPointF,QPoint,QPainterPath.Element],ctrlPt2: Union[QPointF,QPoint,QPainterPath,Element],endPt: Union[QPointF,QPoint,QPainterPath.Element]) | 在当前点和终点间绘制三次贝塞尔曲线,前两个点 是中间控制点,最后一个点是终点 |
cubicTo(ctrlPt1x: float,ctrlPtly: float,ctrlPt2x: float,ctrlPt2y:float,endPtx: float,endPty:float) | 在当前点和终点间绘制三次贝塞尔曲线,前两个点 是中间控制点,最后一个点是终点 |
quadTo(ctrlPt: Union[QPointF,QPoint,QPainterPath.Element],endPt: Union[QPointF,QPoint,QPainterPath.Element]) | 在当前点和终点间添加二次贝塞尔曲线,第一个点 是控制点 |
quadTo(ctrlPtx: float,ctrlPty: float,endPtx: float,endPty: float) | 在当前点和终点间添加二次贝塞尔曲线,第一个点 是控制点 |
arcTo(rect: Union[QRectF,QRect],startAngle: float,arcLength: float) | 在矩形框内绘制圆弧,startAngle和 arcLength分别 是起始角和跨度角. |
arcTo(x: float,y: float,w: float,h: float,startAngle: float,arcLength: float) | 在矩形框内绘制圆弧,startAngle和 arcLength分别 是起始角和跨度角. |
addEllipse(center: Union[QPointF,QPoint],rx: float,ry: float) | 绘制封闭的椭圆 |
addEllipse(rect:Union[QRectF,QRect]) | 绘制封闭的椭圆 |
addEllipse(x: float,y: float,w: float,h:float) | 绘制封闭的椭圆 |
addPolygon(Union[QPolygonF,Sequence[QPointF],QPolygon,QRectF]) | 绘制多边形 |
addRect(rect: Union[QRectF,QRect]) | 绘制矩形 |
addRect(x: float,y: float,w; float,h;float) | 绘制矩形 |
addRoundedRect(rect: Union[QRectF,QRect],xRadius: float,yRadius; float,mode: Qt.SizeMode=Qt.AbsoluteSize) | 绘制圆角矩形 |
addRoundedRect(x: float,y; float,w: float,h: float,xRadius: float,yRadius: float,mode: Qt.SizeMode=Qt.AbsoluteSize) | 绘制圆角矩形 |
addText(point: Union[QPointF,QPoint,QPainterPath.Element],f: Union[QFont,str,Sequence[str]],text: str) | 绘制文本 |
addText(x:float,y: float,f:Union[QFont,str,Sequence[str]],text:str) | 绘制文本 |
addRegion(region: :Union[QRegion,QBitmap,QPolygon,QRect]) | 绘制QRegion的范围 |
closeSubpath() | 由当前子路径首尾绘制直线,开始新的子路径的 绘制 |
connectPath(QPainterPath) | 由当前路径的终点位置与给定路径的起始位置绘制 直线 |
addPath(QPainterPath) | 将其他绘图路径添加进来 |
translate(dx: float,dy: float) | 将绘图路径进行平移,dx和dy是x和y方向的移动 量,或用点表示 |
translate(offset: Union[QPointF,QPoint,QPainterPath.Element]) | 将绘图路径进行平移,dx和dy是x和y方向的移动 量,或用点表示 |
绘图路径QPainterPath 与查询有关的方法
QPainterPath的查询方法 | 返回值的类型 | 说明 |
---|---|---|
angleAtPercent(t: float) | float | 获取绘图路径长度百分比处的切向角 |
slopeAtPercent(t: float) | float | 获取斜率 |
boundingRect() | QRectF | 获取路径所在的边界矩形区域 |
capacity() | int | 返回路径中单元的数量 |
clear() | None | 清空绘图路径中的元素 |
contains(Union[QPointF,QPoint]) | bool | 如果指定的点在路径内部,则返回True |
contains(QRectF) | 6001 | 如果矩形区域在路径内部,则返回True |
contains(QPainterPath) | bool | 如果包含指定的路径,则返回 True |
controlPointRect() | QRectF | 获取包含路径中所有点和控制点构成的矩形 |
elementCount() | int | 获取绘图路径的单元数量 |
intersected(QPainterPath) | QPainterPath | 获取绘图路径和指定路径填充区域相交的 路径 |
united(QPainterPath) | QPainterPath | 获取绘图路径和指定路径填充区域合并的 路径 |
interseets(QRectF) | bo01 | 获取绘图路径与矩形区域是否相交 |
intersects(QPainterPath) | bool | 获取绘图路径与指定路径是否相交 |
subtracted(QPainterPath) | QPainterPath | 获取减去指定路径后的路径 |
isEmpty() | bool | 获取绘图路径是否为空 |
length() | float | 获取绘图路径的长度 |
pointAtPercent(float) | QPointF | 获取百分比长度处的点 |
reserve(size:int) | None | 在内存中预留指定数量的绘图单元内存空间 |
setElementPositionAt(i; int,x; float,y: float) | None | 将索引是int的元素的x和y坐标设置成指 定值 |
setFillRule(Qt.FillRule) | None | 设置填充规则 |
simplified() | QPainterPath | 获取简化后的路径,如果路径元素有交叉或 重合,则简化后的路径没有重合 |
swap(QPainterPath) | None | 交换绘图路径 |
toReversed() | QPainterPath | 获取顺序反转后的绘图路径 |
toSubpathPolygons() | List[QPolygonF] | 将每个元素转换成QPolygonF |
toSubpathPolygons(QTransform) | List[QPolygonF] | 将每个元素转换成QPolygonF |
translated(dx: float,dy: float) | QPainterPath | 获取平动后的绘图路径,float是x方向和y 方向的移动量,或者用点来表示 |
translated(Union[QPointF,QPoint]) | QPainterPath | 获取平动后的绘图路径,float是x方向和y 方向的移动量,或者用点来表示 |
方法说明
路径是由多个图形构成的,每个图形中可能包括直线、贝塞尔曲线、弧、椭圆、多边形、矩形或文本。
- 使用moveTo()方法把当前路径移到指定位置,作为绘图开始的起点位置,移动当前点会启用一个新的子路径,并自动封闭之前的路径
- 绘制
- 用lineTo()方法绘制直线,
- 用arcTo()方法绘制弧,
- 用quadTo()方法和 cubicTo()方法绘制二次和三次贝塞尔曲线,
- 用addEllipse()方法绘制封闭的圆,
- 用addPolygon()方法绘制多边形,
- 用addRect()方法和addRoundedRect()方法绘制矩形。
- 在添加直线、弧或贝塞尔曲线后,当前点移动到这些元素的最后位置。
- 绘制弧时,弧的婴度角与钟表的 3 时方向相同,逆时针方向为正。
- 路径中每个绘图步骤称为单元(element)
- 比如 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个单元构成
- 路径可以进行交、并、减和移动操作。
绘图路径OPainterPath的应用实例
作为应用实例,下面我们绘制一个太极图像,程序中使用非零绕组填充
# -*- coding: UTF-8 -*-
# File date: Hi_2023/3/8 14:19
# File_name: 06-绘图路径QPainterPath 的应用实例.py
from PySide6.QtWidgets import QApplication,QWidget
from PySide6.QtGui import QPen,QPainter,QPainterPath,QBrush
from PySide6.QtCore import QPointF,Qt
import sys
class MyWindow(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.resize(600,500)
def paintEvent(self,event):
path = QPainterPath()# 路径
self.center = QPointF(self.width()/ 2,self.height()/ 2)
r = min(self.width(),self.height())/ 3 # 外面大圆的半径
r1 = r / 7 # 内部小圆的半径
path.moveTo(self.center.x(),self.center.y()- r)
path.arcTo(self.center.x()- r,self.center.y()- r,2 * r,2 * r,90,360)# 外部大圆
path.arcTo(self.center.x()- r,self.center.y()- r,2 * r,2 * r,90,-180)# 反向半圆
path.moveTo(self.center.x(),self.center.y()+ r)
path.arcTo(self.center.x()- r / 2,self.center.y(),r,r,-90,180)# 外部大圆
path.arcTo(self.center.x()- r / 2,self.center.y()- r / 2 - r / 2,r,r,270,-180)# 反向半圆
path.moveTo(self.center.x()+ r1,self.center.y()- r / 2)
path.arcTo(self.center.x()- r1,self.center.y()- r / 2 - r1,2 * r1,2 * r1,0,360)# 内部小圆
path.moveTo(self.center.x()+ r1,self.center.y()+ r / 2)
path.arcTo(self.center.x()- r1,self.center.y()+ r / 2 - r1,2 * r1,2 * r1,0,-360)# 内部小圆
path.setFillRule(Qt.FillRule.WindingFill)# 填充方式
painter = QPainter(self)
pen = QPen()
pen.setWidth(5)
pen.setColor(Qt.black)
painter.setPen(pen)
brush = QBrush(Qt.SolidPattern)
painter.setBrush(brush)# 设置画刷
painter.drawPath(path)# 设置绘制路径
super().paintEvent(event)
if __name__ == '__main__':
app = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(app.exec())