QPainter类在窗口部件或者其他绘图设备上执行底层绘图。QPainter提供了高度优化的绘图功能,可以完成大多数GUI应用所需要的绘图功能。它可以绘制从简单的线条到复杂的形状。可以绘制带对齐方式的文本,也可以绘制像素图。它还可以进行视图和图象的空间坐标变换。QPainter可以在继承自QPaintDevice类的对象上进行绘图操作。
QPainter是一个功能丰富的框架,允许开发人员执行各种图形操作,例如渐变,合成模式和矢量图形。QPainter可以在各种不同的硬件和软件堆栈中执行此操作。
QPainter最常见的用法是在部件的paintEvent()中进行绘图,同时也提供一些和绘图相关的一些功能,比如背景,字符字体,画笔,画刷设置,绘制质量控制以及剪裁操作等。
一些这些函数可以对QPainter绘制要求进行设置:
QPainter绘图设置采用了状态机制的模式,就当前设置,对后续的绘图都起作用。可以随时调用save()函数来保存QPainter的状态,该函数将所有的可用设置保存在内部堆栈中,restore()函数可恢复保存的状态。
QPainter的核心功能是绘图,常用绘图函数有:
QPainter常用绘图函数
为了使用QPainter获得最佳的渲染效果,应使用独立于平台的QImage作为绘制设备; 意思就是使用QImage可以确保绘图结果在任何平台上都具有相同的像素表示。
QPainter提供了一种通过其RenderHint枚举和对浮点精度的支持来控制渲染质量的方法,使用setRenderHint()函数来设置或者清除当前所设置的RenderHints(),其参数有:
通常情况下,QPainter在设备自身的坐标系(通常为像素)上运行,但是QPainter对坐标转换有很好的支持。
最常用的转换是缩放,旋转,平移和扭曲:
示例代码演示了各种设置下使用QPainter绘制基本形状。完整代码如下:
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt, QPoint, QSize, QRect, pyqtSignal
from PyQt5.QtGui import (QPolygon, QPen, QBrush, QPainter, QPixmap, QConicalGradient,
QLinearGradient, QRadialGradient, QPainterPath, QPalette,
QColor, QIcon)
from PyQt5.QtWidgets import (QApplication, QWidget, QCheckBox, QComboBox, QLabel, QSpinBox,
QFormLayout, QHBoxLayout, QSizePolicy, QColorDialog, QFrame)
import resource_rc
#颜色选择按钮
class ColorButton(QFrame):
colorChanged = pyqtSignal()
clicked = pyqtSignal()
def __init__(self, clr = Qt.blue, parent= None):
super(ColorButton, self).__init__(parent)
self.setAutoFillBackground(True)
self.setFrameShape(QFrame.Box)
self.setFrameShadow(QFrame.Plain)
self.setLineWidth(1)
self.setMinimumHeight(20)
self.__color = clr
self.clicked.connect(self.getColor)
self.setColor(clr)
def setColor(self, newColor):
pal = self.palette()
pal.setColor(QPalette.Window, newColor)
self.setPalette(pal)
self.__color = newColor
self.colorChanged.emit()
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton:
self.clicked.emit()
else:
super(ColorButton, self).mousePressEvent(event)
def getColor(self):
color = QColorDialog.getColor(self.__color)
if color != self.__color:
self.setColor(color)
def color(self):
return self.__color
#渲染区域
class RenderArea(QWidget):
Line, Points, Polyline, Polygon, Rect, RoundedRect, Ellipse, Arc, \
Chord, Pie, Path, Text, Pixmap = range(13)
def __init__(self, parent=None):
super(RenderArea, self).__init__(parent)
self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
self.pen = QPen()
self.brush = QBrush()
self.pixmap = QPixmap()
#抗锯齿控制
self.antialiased = False
#加载用于填充的位图
self.pixmap.load(':/images/python-logo.png')
#缺省形状
self.shape = RenderArea.Polygon
#背景填充
self.setBackgroundRole(QPalette.Base)
self.setAutoFillBackground(True)
#绘图区域最小尺寸
def minimumSizeHint(self):
return QSize(400,400)
#绘图区域缺省尺寸
def sizeHint(self):
return QSize(400, 400)
def setShape(self, shape):
self.shape = shape
self.update()
def setPen(self, pen):
self.pen = pen
self.update()
def setBrush(self, brush):
self.brush = brush
self.update()
def setAntialiased(self, antialiased):
self.antialiased = antialiased
self.update()
def paintEvent(self, event):
painter = QPainter(self)
painter.setPen(self.pen)
painter.setBrush(self.brush)
if(self.antialiased):
painter.setRenderHint(QPainter.Antialiasing)
rect = QRect(50,100,300,200)
points = QPolygon([QPoint(150,100),QPoint(300,150),QPoint(350,250),QPoint(100,300)])
startAngle = 30 * 16
spanAngle = 120 * 16
path = QPainterPath()
#path.addRect(150,150,100,100)
path.moveTo(100,100)
path.cubicTo(300,100,200,200,300,300)
path.cubicTo(100,300,200,200,100,100)
if self.shape == RenderArea.Line:
painter.drawLine(rect.topLeft(), rect.bottomRight())
elif self.shape == RenderArea.Points:
painter.drawPoints(points)
elif self.shape == RenderArea.Polyline:
painter.drawPolyline(points)
elif self.shape == RenderArea.Polygon:
painter.drawPolygon(points)
elif self.shape == RenderArea.Rect:
painter.drawRect(rect)
elif self.shape == RenderArea.RoundedRect:
painter.drawRoundedRect(rect, 25, 25, Qt.RelativeSize)
elif self.shape == RenderArea.Ellipse:
painter.drawEllipse(rect)
elif self.shape == RenderArea.Arc:
painter.drawArc(rect, startAngle, spanAngle)
elif self.shape == RenderArea.Chord:
painter.drawChord(rect, startAngle, spanAngle)
elif self.shape == RenderArea.Pie:
painter.drawPie(rect, startAngle, spanAngle)
elif self.shape == RenderArea.Path:
painter.drawPath(path)
elif self.shape == RenderArea.Text:
painter.drawText(self.rect(), Qt.AlignCenter, 'Qt for python')
elif self.shape == RenderArea.Pixmap:
painter.drawPixmap(150, 150, self.pixmap)
#边框
painter.setPen(self.palette().dark().color())
painter.setBrush(Qt.NoBrush)
painter.drawRect(QRect(0,0, self.width()-1, self.height()-1))
class DemoPainter(QWidget):
def __init__(self, parent=None):
super(DemoPainter, self).__init__(parent)
# 设置窗口标题
self.setWindowTitle('实战 Qt for Python: QPainter演示')
# 设置窗口大小
self.resize(600, 400)
self.initUi()
def initUi(self):
self.renderArea = RenderArea()
self.brushColor = Qt.green
formLayout = QFormLayout()
#形状控制
self.shapeComboBox = QComboBox()
self.shapeComboBox.addItem('Polygon', RenderArea.Polygon)
self.shapeComboBox.addItem('Rectangle', RenderArea.Rect)
self.shapeComboBox.addItem("Rounded Rectangle", RenderArea.RoundedRect)
self.shapeComboBox.addItem("Ellipse", RenderArea.Ellipse)
self.shapeComboBox.addItem("Pie", RenderArea.Pie)
self.shapeComboBox.addItem("Chord", RenderArea.Chord)
self.shapeComboBox.addItem("Path", RenderArea.Path)
self.shapeComboBox.addItem("Line", RenderArea.Line)
self.shapeComboBox.addItem("Polyline", RenderArea.Polyline)
self.shapeComboBox.addItem("Arc", RenderArea.Arc)
self.shapeComboBox.addItem("Points", RenderArea.Points)
self.shapeComboBox.addItem("Text", RenderArea.Text)
self.shapeComboBox.addItem("Pixmap", RenderArea.Pixmap)
self.shapeComboBox.activated.connect(self.shapeChanged)
shapeLabel = QLabel('形状(&S):')
shapeLabel.setBuddy(self.shapeComboBox)
#线宽控制
self.penWidthSpinBox = QSpinBox()
self.penWidthSpinBox.setRange(0, 20)
self.penWidthSpinBox.setSpecialValueText('0 (cosmetic pen')
self.penWidthSpinBox.valueChanged.connect(self.penChanged)
penWidthLabel = QLabel('画笔线宽(&W):')
penWidthLabel.setBuddy(self.penWidthSpinBox)
#画笔颜色控制
self.penColorButton = ColorButton()
self.penColorButton.colorChanged.connect(self.penChanged)
penColorLabel = QLabel('画笔颜色(&C):')
penColorLabel.setBuddy(self.penColorButton)
#画笔线型控制
self.penStyleComboBox = QComboBox()
self.penStyleComboBox.addItem('Solid', Qt.SolidLine)
self.penStyleComboBox.addItem('Dash', Qt.DashLine)
self.penStyleComboBox.addItem('Dot', Qt.DotLine)
self.penStyleComboBox.addItem('Dash Dot', Qt.DashDotLine)
self.penStyleComboBox.addItem('Dash Dot Dot', Qt.DashDotDotLine)
self.penStyleComboBox.addItem('None', Qt.NoPen)
self.penStyleComboBox.activated.connect(self.penChanged)
penStyleLabel = QLabel("画笔线型(&P):")
penStyleLabel.setBuddy(self.penStyleComboBox)
#笔尖样式
self.penCapComboBox = QComboBox()
self.penCapComboBox.addItem("Flat", Qt.FlatCap)
self.penCapComboBox.addItem("Square", Qt.SquareCap)
self.penCapComboBox.addItem("Round", Qt.RoundCap)
self.penCapComboBox.activated.connect(self.penChanged)
penCapLabel = QLabel("笔尖样式(&C):")
penCapLabel.setBuddy(self.penCapComboBox)
#连接方式
self.penJoinComboBox = QComboBox()
self.penJoinComboBox.addItem("Miter", Qt.MiterJoin)
self.penJoinComboBox.addItem("Bevel", Qt.BevelJoin)
self.penJoinComboBox.addItem("Round", Qt.RoundJoin)
self.penJoinComboBox.activated.connect(self.penChanged)
penJoinLabel = QLabel("连接方式(&J):")
penJoinLabel.setBuddy(self.penJoinComboBox)
#画刷填充模式
self.brushStyleComboBox = QComboBox()
self.brushStyleComboBox.addItem("Linear Gradient",
Qt.LinearGradientPattern)
self.brushStyleComboBox.addItem("Radial Gradient",
Qt.RadialGradientPattern)
self.brushStyleComboBox.addItem("Conical Gradient",
Qt.ConicalGradientPattern)
self.brushStyleComboBox.addItem("Texture", Qt.TexturePattern)
self.brushStyleComboBox.addItem("Solid", Qt.SolidPattern)
self.brushStyleComboBox.addItem("Horizontal", Qt.HorPattern)
self.brushStyleComboBox.addItem("Vertical", Qt.VerPattern)
self.brushStyleComboBox.addItem("Cross", Qt.CrossPattern)
self.brushStyleComboBox.addItem("Backward Diagonal", Qt.BDiagPattern)
self.brushStyleComboBox.addItem("Forward Diagonal", Qt.FDiagPattern)
self.brushStyleComboBox.addItem("Diagonal Cross", Qt.DiagCrossPattern)
self.brushStyleComboBox.addItem("Dense 1", Qt.Dense1Pattern)
self.brushStyleComboBox.addItem("Dense 2", Qt.Dense2Pattern)
self.brushStyleComboBox.addItem("Dense 3", Qt.Dense3Pattern)
self.brushStyleComboBox.addItem("Dense 4", Qt.Dense4Pattern)
self.brushStyleComboBox.addItem("Dense 5", Qt.Dense5Pattern)
self.brushStyleComboBox.addItem("Dense 6", Qt.Dense6Pattern)
self.brushStyleComboBox.addItem("Dense 7", Qt.Dense7Pattern)
self.brushStyleComboBox.addItem("None", Qt.NoBrush)
self.brushStyleComboBox.activated.connect(self.brushChanged)
brushStyleLabel = QLabel("填充模式(&):")
brushStyleLabel.setBuddy(self.brushStyleComboBox)
#画刷颜色控制
self.brushColorButton = ColorButton(self.brushColor)
self.brushColorButton.colorChanged.connect(self.brushColorChanged)
brushColorLabel = QLabel('画刷颜色(&C):')
brushColorLabel.setBuddy(self.brushColorButton)
#抗锯齿
self.antialiasingCheckBox = QCheckBox('抗锯齿(&A)')
self.antialiasingCheckBox.toggled.connect(self.renderArea.setAntialiased)
formLayout.addRow(shapeLabel, self.shapeComboBox)
formLayout.addRow(penWidthLabel, self.penWidthSpinBox)
formLayout.addRow(penColorLabel, self.penColorButton)
formLayout.addRow(penStyleLabel, self.penStyleComboBox)
formLayout.addRow(penCapLabel, self.penCapComboBox)
formLayout.addRow(penJoinLabel, self.penJoinComboBox)
formLayout.addRow(brushStyleLabel, self.brushStyleComboBox)
formLayout.addRow(brushColorLabel, self.brushColorButton)
formLayout.addRow('', self.antialiasingCheckBox)
mainLayout = QHBoxLayout()
mainLayout.setSpacing(20)
mainLayout.addWidget(self.renderArea)
mainLayout.addLayout(formLayout)
self.setLayout(mainLayout)
self.shapeChanged()
self.penChanged()
self.brushChanged()
self.antialiasingCheckBox.setChecked(True)
def shapeChanged(self):
shape = self.shapeComboBox.itemData(self.shapeComboBox.currentIndex(), Qt.UserRole)
self.renderArea.setShape(shape)
def penChanged(self):
width = self.penWidthSpinBox.value()
color = self.penColorButton.color()
style = Qt.PenStyle(self.penStyleComboBox.itemData(
self.penStyleComboBox.currentIndex(), Qt.UserRole))
cap = Qt.PenCapStyle(self.penCapComboBox.itemData(
self.penCapComboBox.currentIndex(), Qt.UserRole))
join = Qt.PenJoinStyle(self.penJoinComboBox.itemData(
self.penJoinComboBox.currentIndex(), Qt.UserRole))
self.renderArea.setPen(QPen(color, width, style, cap, join))
def brushChanged(self):
style = Qt.BrushStyle(self.brushStyleComboBox.itemData(
self.brushStyleComboBox.currentIndex(), Qt.UserRole))
#style = Qt.HorPattern
if style == Qt.LinearGradientPattern:
linearGradient = QLinearGradient(0, 0, 400, 400)
linearGradient.setColorAt(0.0, Qt.white)
linearGradient.setColorAt(0.2, self.brushColor)
linearGradient.setColorAt(1.0, Qt.black)
self.renderArea.setBrush(QBrush(linearGradient))
elif style == Qt.RadialGradientPattern:
radialGradient = QRadialGradient(200, 200, 80, 70, 70)
radialGradient.setColorAt(0.0, Qt.white)
radialGradient.setColorAt(0.2, self.brushColor)
radialGradient.setColorAt(1.0, Qt.black)
self.renderArea.setBrush(QBrush(radialGradient))
elif style == Qt.ConicalGradientPattern:
conicalGradient = QConicalGradient(200, 200, 30)
conicalGradient.setColorAt(0.0, Qt.white)
conicalGradient.setColorAt(0.2, self.brushColor)
conicalGradient.setColorAt(1.0, Qt.black)
self.renderArea.setBrush(QBrush(conicalGradient))
elif style == Qt.TexturePattern:
self.renderArea.setBrush(QBrush(QPixmap(':/images/brick.png')))
else:
self.renderArea.setBrush(QBrush(self.brushColor, style))
def brushColorChanged(self):
color = self.brushColorButton.color()
if color != self.brushColor:
self.brushColor = color
self.brushChanged()
if __name__ == '__main__':
app = QApplication(sys.argv)
window = DemoPainter()
window.show()
sys.exit(app.exec())
Qpainter绘图演示
前一篇: 122-使用QMovie实现GIF动画播放