QPainter 绘图 ( QPen )
使用 PyQt6 的 QPainter 绘图时,通常都会透过 QPen 设定画笔的颜色与样式,这篇教学会介绍 QPen 常用的功能以及设定画笔的指令。
快速导览:
因为 Google Colab 不支援 PyQt6,所以请使用本机环境 ( 参考:使用 Python 虚拟环境 ) 或使用 Anaconda Jupyter 进行实作 ( 参考:使用 Anaconda )。
开始使用 QPen
QPen 通常是搭配 QPainter 的 setPen 方法一起使用,最基本的用法如下 ( 方法的位置和 PyQt5 有所不同 ):
qpainter = QPainter()
qpainter.setPen(QPen(QColor, width, Qt.PenStyle, Qt.PenCapStyle, Qt.PenJoinStyle))
QPen 基本的用法需要设定下列参数:
| 参数 | 说明 |
|---|---|
| QColor | 设定颜色。 |
| width | 画笔宽度。 |
| Qt.PenStyle | 画笔样式。 |
| Qt.PenCapStyle | 线段开头与结尾样式。 |
| Qt.PenJoinStyle | 线段连接处样式。 |
下方的程序码执行后,画面中的两个正方形虽然大小相同,但因为 QPen 的参数设定不同而产生的样式就会不同。
请先阅读:QPainter 绘图
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("oxxo.studio")
MainWindow.resize(300, 200)
def draw(self):
qpainter = QPainter()
qpainter.begin(MainWindow)
# 左邊的正方形
qpainter.setPen(QPen(QColor('#000000'), 5, Qt.PenStyle.DotLine, Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.MiterJoin))
qpainter.drawRect(30,50,100,100)
# 右邊的正方形
qpainter.setPen(QPen(QColor('#ff0000'), 10, Qt.PenStyle.DashDotDotLine, Qt.PenCapStyle.RoundCap, Qt.PenJoinStyle.RoundJoin))
qpainter.drawRect(160,50,100,100)
qpainter.end()
MainWindow.paintEvent = draw
MainWindow.show()
sys.exit(app.exec())
class 写法:
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setObjectName("MainWindow")
self.setWindowTitle('oxxo.studio')
self.resize(300, 200)
def paintEvent(self, event):
self.qpainter = QPainter()
self.qpainter.begin(self)
# 左邊的正方形
self.qpainter.setPen(QPen(QColor('#000000'), 5, Qt.PenStyle.DotLine, Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.MiterJoin))
self.qpainter.drawRect(30,50,100,100)
# 右邊的正方形
self.qpainter.setPen(QPen(QColor('#ff0000'), 10, Qt.PenStyle.DashDotDotLine, Qt.PenCapStyle.RoundCap, Qt.PenJoinStyle.RoundJoin))
self.qpainter.drawRect(160,50,100,100)
self.qpainter.end()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
Form = MyWidget()
Form.show()
sys.exit(app.exec())
除了设定参数的方法,也可以先建立 QPen 对象,再透过对象本身提供的属性进行设定,例如下方的程序码,将黑色虚线的正方形改用 QPen 对象的设定方法,也能得到一模一样的结果。
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("oxxo.studio")
MainWindow.resize(300, 200)
def draw(self):
qpainter = QPainter()
qpainter.begin(MainWindow)
qpen = QPen() # 建立 QPen 物件
qpen.setColor(QColor('#000000')) # 設定顏色
qpen.setWidth(5) # 設定寬度
qpen.setStyle(Qt.PenStyle.DotLine) # 設定樣式
qpen.setCapStyle(Qt.PenCapStyle.FlatCap) # 設定線段開頭與結尾樣式
qpen.setJoinStyle(Qt.PenJoinStyle.MiterJoin) # 設定線段連接處樣式
qpainter.setPen(qpen) # 效果等同下方
# qpainter.setPen(QPen(QColor('#000000'), 5, Qt.PenStyle.DotLine, Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.MiterJoin))
qpainter.drawRect(30,50,100,100)
qpainter.setPen(QPen(QColor('#ff0000'), 10, Qt.PenStyle.DashDotDotLine, Qt.PenCapStyle.RoundCap, Qt.PenJoinStyle.RoundJoin))
qpainter.drawRect(160,50,100,100)
qpainter.end()
MainWindow.paintEvent = draw
MainWindow.show()
sys.exit(app.exec())
class 写法:
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setObjectName("MainWindow")
self.setWindowTitle('oxxo.studio')
self.resize(300, 200)
def paintEvent(self, event):
self.qpainter = QPainter()
self.qpainter.begin(self)
qpen = QPen() # 建立 QPen 物件
qpen.setColor(QColor('#000000')) # 設定顏色
qpen.setWidth(5) # 設定寬度
qpen.setStyle(Qt.PenStyle.DotLine) # 設定樣式
qpen.setCapStyle(Qt.PenCapStyle.FlatCap) # 設定線段開頭與結尾樣式
qpen.setJoinStyle(Qt.PenJoinStyle.MiterJoin) # 設定線段連接處樣式
self.qpainter.setPen(qpen) # 效果等同下方
# self.qpainter.setPen(QPen(QColor('#000000'), 5, Qt.PenStyle.DotLine, Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.MiterJoin))
self.qpainter.drawRect(30,50,100,100)
self.qpainter.setPen(QPen(QColor('#ff0000'), 10, Qt.PenStyle.DashDotDotLine, Qt.PenCapStyle.RoundCap, Qt.PenJoinStyle.RoundJoin))
self.qpainter.drawRect(160,50,100,100)
self.qpainter.end()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
Form = MyWidget()
Form.show()
sys.exit(app.exec())
QPen 画笔颜色与宽度
QPen 设定画笔宽度只需要填入一个数字,单位是像素,但设定颜色则需要搭配 PyQt6.QtGui 模组里的 QColor 方法,QColor 常使用两种方式设定颜色,第一种方法直接填入十六进制色码:
QColor('#ff0000') # 紅色
QColor('#00ff00') # 綠色
QColor('#0000ff') # 藍色
第二种方法可以填入 Red、Green、Blue 和 Alpha ( 透明度,不填默认 255 ) 的数值,数值范围 0~255:
QColor(255, 0, 0) # 紅色
QColor(255, 0, 0, 50) # 半透明紅色
QColor(0, 255, 0, 255) # 綠色
QColor(0, 0, 255, 100) # 半透明藍色
下方的例子执行后,会出现两个边框透明度不同的正方形。
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("oxxo.studio")
MainWindow.resize(300, 200)
def draw(self):
qpainter = QPainter()
qpainter.begin(MainWindow)
qpainter.setPen(QPen(QColor(255,0,0), 10)) # 紅色
qpainter.drawRect(30,50,100,100)
qpainter.setPen(QPen(QColor(255,0,0,50), 10)) # 半透明紅色
qpainter.drawRect(160,50,100,100)
qpainter.end()
MainWindow.paintEvent = draw
MainWindow.show()
sys.exit(app.exec())
class 写法:
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setObjectName("MainWindow")
self.setWindowTitle('oxxo.studio')
self.resize(300, 200)
def paintEvent(self, event):
self.qpainter = QPainter()
self.qpainter.begin(self)
self.qpainter.setPen(QPen(QColor(255,0,0), 10)) # 紅色
self.qpainter.drawRect(30,50,100,100)
self.qpainter.setPen(QPen(QColor(255,0,0,50), 10)) # 半透明紅色
self.qpainter.drawRect(160,50,100,100)
self.qpainter.end()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
Form = MyWidget()
Form.show()
sys.exit(app.exec())
QPen 画笔样式
QPen 总共有六种画笔样式:
| 样式名称 | 说明 |
|---|---|
| Qt.PenStyle.SolidLine | 实线。 |
| Qt.PenStyle.DashLine | 虚线。 |
| Qt.PenStyle.DotLine | 点状线。 |
| Qt.PenStyle.DashDotLine | 一点状线混合虚线。 |
| Qt.PenStyle.DashDotDotLine | 两点状线混合虚线。 |
| Qt.PenStyle.CustomDashLine | 自订虚线。 |
使用时只有自订虚线 Qt.CustomDashLine 需要搭配 setDashPattern 方法额外设定,setDashPattern 方法可以指定虚线和空白间隔的长度,例如下方的程序码执行后,就会出现六种样式的线条。
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("oxxo.studio")
MainWindow.resize(300, 200)
def draw(self):
qpainter = QPainter()
qpainter.begin(MainWindow)
qpainter.setPen(QPen(QColor(0,0,0), 6, Qt.PenStyle.SolidLine)) # 實線
qpainter.drawLine(50, 40, 250, 40)
qpainter.setPen(QPen(QColor(0,0,0), 6, Qt.PenStyle.DashLine)) # 虛線
qpainter.drawLine(50, 60, 250, 60)
qpainter.setPen(QPen(QColor(0,0,0), 6, Qt.PenStyle.DotLine)) # 點狀線
qpainter.drawLine(50, 80, 250, 80)
qpainter.setPen(QPen(QColor(0,0,0), 6, Qt.PenStyle.DashDotLine)) # 一點狀線混合虛線
qpainter.drawLine(50, 100, 250, 100)
qpainter.setPen(QPen(QColor(0,0,0), 6, Qt.PenStyle.DashDotDotLine)) # 兩點狀線混合虛線
qpainter.drawLine(50, 120, 250, 120)
qpen = QPen()
qpen.setColor(QColor(0,0,0))
qpen.setWidth(6)
space = 4 # 空白長度
dashes = [1, space, 3, space, 9, space, 5, space, 1, space] # 自訂虛線樣式,偶數為空白
qpen.setDashPattern(dashes) # 設定虛線樣式
qpen.setStyle(Qt.PenStyle.CustomDashLine) # 自訂虛線
qpainter.setPen(qpen)
qpainter.drawLine(50, 140, 250, 140)
qpainter.end()
MainWindow.paintEvent = draw
MainWindow.show()
sys.exit(app.exec())
class 写法:
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setObjectName("MainWindow")
self.setWindowTitle('oxxo.studio')
self.resize(300, 200)
def paintEvent(self, event):
self.qpainter = QPainter()
self.qpainter.begin(self)
self.qpainter.setPen(QPen(QColor(0,0,0), 6, Qt.PenStyle.SolidLine)) # 實線
self.qpainter.drawLine(50, 40, 250, 40)
self.qpainter.setPen(QPen(QColor(0,0,0), 6, Qt.PenStyle.DashLine)) # 虛線
self.qpainter.drawLine(50, 60, 250, 60)
self.qpainter.setPen(QPen(QColor(0,0,0), 6, Qt.PenStyle.DotLine)) # 點狀線
self.qpainter.drawLine(50, 80, 250, 80)
self.qpainter.setPen(QPen(QColor(0,0,0), 6, Qt.PenStyle.DashDotLine)) # 一點狀線混合虛線
self.qpainter.drawLine(50, 100, 250, 100)
self.qpainter.setPen(QPen(QColor(0,0,0), 6, Qt.PenStyle.DashDotDotLine)) # 兩點狀線混合虛線
self.qpainter.drawLine(50, 120, 250, 120)
qpen = QPen()
qpen.setColor(QColor(0,0,0))
qpen.setWidth(6)
space = 4 # 空白長度
dashes = [1, space, 3, space, 9, space, 5, space, 1, space] # 自訂虛線樣式,偶數為空白
qpen.setDashPattern(dashes) # 設定虛線樣式
qpen.setStyle(Qt.PenStyle.CustomDashLine) # 自訂虛線
self.qpainter.setPen(qpen)
self.qpainter.drawLine(50, 140, 250, 140)
self.qpainter.end()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
Form = MyWidget()
Form.show()
sys.exit(app.exec())
QPen 线段开头与结尾样式
QPen 总共有三种线段开头与结尾样式:
| 线段开头与结尾样式 | 说明 |
|---|---|
| Qt.PenCapStyle.SquareCap | 平面样式,会超过端点线宽的一半的距离。 |
| Qt.PenCapStyle.FlatCap | 平面样式,会切齐端点。 |
| Qt.PenCapStyle.RoundCap | 圆形样式,中心点对齐端点。 |
下方的程序码执行后,会先画使用 Qt.FlatCap 切齐端点的黑线,接着在画三条开头与结尾样式不同的半透明粗红线。
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("oxxo.studio")
MainWindow.resize(300, 200)
def draw(self):
qpainter = QPainter()
qpainter.begin(MainWindow)
qpainter.setPen(QPen(QColor(0,0,0), 2, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap))
qpainter.drawLine(50, 40, 250, 40)
qpainter.setPen(QPen(QColor(0,0,0), 2, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap))
qpainter.drawLine(50, 80, 250, 80)
qpainter.setPen(QPen(QColor(0,0,0), 2, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap))
qpainter.drawLine(50, 120, 250, 120)
qpainter.setPen(QPen(QColor(255,0,0,50), 20, Qt.PenStyle.SolidLine, Qt.PenCapStyle.SquareCap))
qpainter.drawLine(50, 40, 250, 40)
qpainter.setPen(QPen(QColor(255,0,0,50), 20, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap))
qpainter.drawLine(50, 80, 250, 80)
qpainter.setPen(QPen(QColor(255,0,0,50), 20, Qt.PenStyle.SolidLine, Qt.PenCapStyle.RoundCap))
qpainter.drawLine(50, 120, 250, 120)
qpainter.end()
MainWindow.paintEvent = draw
MainWindow.show()
sys.exit(app.exec())
class 写法:
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setObjectName("MainWindow")
self.setWindowTitle('oxxo.studio')
self.resize(300, 200)
def paintEvent(self, event):
self.qpainter = QPainter()
self.qpainter.begin(self)
self.qpainter.setPen(QPen(QColor(0,0,0), 2, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap))
self.qpainter.drawLine(50, 40, 250, 40)
self.qpainter.setPen(QPen(QColor(0,0,0), 2, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap))
self.qpainter.drawLine(50, 80, 250, 80)
self.qpainter.setPen(QPen(QColor(0,0,0), 2, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap))
self.qpainter.drawLine(50, 120, 250, 120)
self.qpainter.setPen(QPen(QColor(255,0,0,50), 20, Qt.PenStyle.SolidLine, Qt.PenCapStyle.SquareCap))
self.qpainter.drawLine(50, 40, 250, 40)
self.qpainter.setPen(QPen(QColor(255,0,0,50), 20, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap))
self.qpainter.drawLine(50, 80, 250, 80)
self.qpainter.setPen(QPen(QColor(255,0,0,50), 20, Qt.PenStyle.SolidLine, Qt.PenCapStyle.RoundCap))
self.qpainter.drawLine(50, 120, 250, 120)
self.qpainter.end()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
Form = MyWidget()
Form.show()
sys.exit(app.exec())
QPen 线段连接处样式
QPen 总共有三种线段连接处样式:
| 线段连接处样式 | 说明 |
|---|---|
| Qt.PenJoinStyle.BevelJoin | 平面。 |
| Qt.PenJoinStyle.MiterJoin | 延伸线条。 |
| Qt.PenJoinStyle.RoundJoin | 圆弧。 |
下方的程序码执行后,会画出三条线段连接处样式不同的粗红线。
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
MainWindow.setObjectName("MainWindow")
MainWindow.setWindowTitle("oxxo.studio")
MainWindow.resize(300, 200)
def draw(self):
qpainter = QPainter()
qpainter.begin(MainWindow)
qpainter.setPen(QPen(QColor(255,0,0), 25, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.BevelJoin))
points = [QPoint(30,160),QPoint(60,50),QPoint(90,160)]
qpainter.drawPolyline(points)
qpainter.setPen(QPen(QColor(255,0,0), 25, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.MiterJoin))
points = [QPoint(120,160),QPoint(150,50),QPoint(180,160)]
qpainter.drawPolyline(points)
qpainter.setPen(QPen(QColor(255,0,0), 25, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.RoundJoin))
points = [QPoint(210,160),QPoint(240,50),QPoint(270,160)]
qpainter.drawPolyline(points)
qpainter.end()
MainWindow.paintEvent = draw
MainWindow.show()
sys.exit(app.exec())
class 写法:
from PyQt6 import QtWidgets
from PyQt6.QtGui import *
from PyQt6.QtCore import *
import sys
class MyWidget(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.setObjectName("MainWindow")
self.setWindowTitle('oxxo.studio')
self.resize(300, 200)
def paintEvent(self, event):
self.qpainter = QPainter()
self.qpainter.begin(self)
self.qpainter.setPen(QPen(QColor(255,0,0), 25, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.BevelJoin))
points = [QPoint(30,160),QPoint(60,50),QPoint(90,160)]
self.qpainter.drawPolyline(points)
self.qpainter.setPen(QPen(QColor(255,0,0), 25, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.MiterJoin))
points = [QPoint(120,160),QPoint(150,50),QPoint(180,160)]
self.qpainter.drawPolyline(points)
self.qpainter.setPen(QPen(QColor(255,0,0), 25, Qt.PenStyle.SolidLine, Qt.PenCapStyle.FlatCap, Qt.PenJoinStyle.RoundJoin))
points = [QPoint(210,160),QPoint(240,50),QPoint(270,160)]
self.qpainter.drawPolyline(points)
self.qpainter.end()
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
Form = MyWidget()
Form.show()
sys.exit(app.exec())
参考数据
微信扫码关注
抖音扫码关注