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())
參考資料
意見回饋
如果有任何建議或問題,可傳送「意見表單」給我,謝謝~