PyQt5-QPainter绘图
QPainter绘图系统
paintEvent事件和绘图区
PyQt5的绘图系统使用户可以在屏幕或打印设备上用相同的API绘图,QPainter是用来进行绘图操作的类,一般的绘图设备包括QWidget、QPixmap、QImage等,这些绘图设备为QPainter提供了一个“画布”。
QWidget类是所有界面组件的基类,QWidget类有一个paintEvent()事件,在此事件里创建一个QPainter对象获取绘图设备的接口,就可以用QPainter对象在绘图设备的“画布”上绘图了。
首先创建一个属于本绘图设备的QPainter对象painter,然后使用这个painter在绘图设备的窗口上画图。
QWidget的内部绘图区的坐标系统如图8-1所示,坐标系统的单位是像素。左上角坐标为(0, 0),向右是x轴正方向,向下是y轴正方向,绘图区的宽度由QWidget.width()函数得到,高度由QWidget.height()函数得到。这个坐标系统是QWidget的绘图区的局部物理坐标,称为视口(viewport)坐标。相应的还有逻辑坐标,称为窗口(window)坐标,后面会详细介绍。使用QPainter在QWidget上绘图就是在这样的一个矩形区域里绘图。
QPainter绘图的主要属性
用QPainter在绘图设备上绘图,主要是绘制一些基本的图形元素,包括点、直线、圆形、矩形、曲线、文字等,控制这些绘图元素特性的主要是QPainter的以下3个属性。
· pen属性是一个QPen对象,用于控制线条的颜色、宽度、线型等,图8-1中矩形边框的线条的特性就是由pen属性决定的。
· brush属性是一个QBrush对象,用于设置一个区域的填充特性,可以设置填充颜色、填充方式、渐变特性等,还可以采用图片做材质填充。图8-1中的矩形用黄色填充就是由brush属性决定的。
· font属性是一个QFont对象,用于绘制文字时,设置文字的字体样式、大小等属性。
使用这3个属性基本就控制了绘图的基本特点,当然还有一些其他的功能可以结合使用,例如叠加模式、旋转和缩放等功能。
示例程序结构
为演示QPainter绘图的基本功能,使用QPainter对象在一个QWidget窗体的paintEvent()事件函数里直接绘图。界面上无需其他任何组件,所以不创建UI文件,直接创建一个myWidget.py文件,该文件的完整代码如下(此处的import部分还包含了后面的示例代码中要用到的各种类),运行后可得到如图8-1所示的效果。
import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)
class QmyWidget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
self.setAutoFillBackground(True)
self.resize(400,280)
self.setWindowTitle("QPainter基本绘图")
def paintEvent(self, event): #在窗口上绘图
painter=QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.setRenderHint(QPainter.TextAntialiasing)
##设置画笔
pen=QPen()
pen.setWidth(3) #线宽
pen.setColor(Qt.red) #画线颜色
pen.setStyle(Qt.SolidLine) #线的类型,如实线、虚线等
pen.setCapStyle(Qt.FlatCap)# 线端点样式
pen.setJoinStyle(Qt.BevelJoin)# 线的连接点样式
painter.setPen(pen)
##设置画刷
brush = QBrush()
brush.setColor(Qt.yellow)
# 画刷颜色
brush.setStyle(Qt.SolidPattern) # 填充样式
painter.setBrush(brush)
##绘图
W = self.width()
# 绘图区宽度
H = self.height()
# 绘图区高度
rect=QRect(W/4,H/4,W/2,H/2)
painter.drawRect(rect)
if __name__ == "__main__": ##用于当前窗体测试
app=QApplication(sys.argv) #创建GUI应用程序
form=QmyWidget() #创建窗体
form.show()
sys.exit(app.exec_())
运行之后的效果图:
构造函数中设置窗口背景颜色为白色,并设置为自动重绘背景。绘图功能在paintEvent()事件函数里实现,该函数的代码主要包括以下几部分。
· 创建与QWidget对象关联的QPainter对象painter,这样就可以用这个painter在窗体上绘图了。用setRenderHint()设置使用抗锯齿功能,会使图和文字更光滑清晰,但也更消耗运算时间。
· 创建一个QPen类对象pen,设置其线宽、颜色、线型等,然后设置为painter的pen。
· 创建一个QBrush类对象brush,设置其颜色为黄色、填充方式为实体填充,然后设置为painter的brush。
· 获取窗体的宽度和高度,并定义位于中间区域的矩形rect,这个矩形的大小随窗体的大小变化而变化。
· 执行painter.drawRect(rect)就可以绘制矩形rect,矩形框的线条特性由pen属性决定,填充特性由brush属性决定。运行程序就可以得到如图8-1所示的居于窗体中间的填充矩形。
为了不使程序结构过于复杂,可以在paintEvent()函数里直接设置pen和brush的各种属性,而不是设计复杂的界面来修改这些设置。要实现想要的绘图功能和效果,只需在paintEvent()函数里直接修改代码即可。
QPen的主要功能
QPen用于绘图时设置线条,主要包括线宽、颜色、线型等,表8-1是QPen类的主要接口函数。通常每个设置函数都有一个对应的读取函数,例如setColor()用于设置画笔颜色,对应的读取画笔颜色的函数为color(),表8-1仅列出了设置函数,这些函数都没有返回值。
线条颜色和宽度的设置无须多说,QPen影响线条特性的另外3个主要属性是线条样式(style)、线条端点样式(capStyle)和线条连接样式(joinStyle)。
import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)
class QmyWidget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
self.setAutoFillBackground(True)
self.resize(400,280)
self.setWindowTitle("QPainter基本绘图")
def paintEvent(self, event):
painter=QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.setRenderHint(QPainter.TextAntialiasing)
##设置画笔
pen=QPen()
pen.setWidth(2) #线宽
pen.setColor(Qt.red) #画线颜色
painter.setPen(pen)
##设置画刷
texturePixmap=QPixmap("1.jpg")
brush = QBrush()
brush.setStyle(Qt.TexturePattern)
brush.setTexture(texturePixmap)
painter.setBrush(brush)
##绘图
W = self.width()
# 绘图区宽度
H = self.height()
# 绘图区高度
rect=QRect(W/5,H/5,3*W/5,3*H/5)
painter.drawRect(rect)
if __name__ == "__main__": ##用于当前窗体测试
app=QApplication(sys.argv) #创建GUI应用程序
form=QmyWidget() #创建窗体
form.show()
sys.exit(app.exec_())
例如,使用QLinearGradient绘制一个渐变填充的矩形区域的paintEvent()事件函数的代码如下:
import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)
class QmyWidget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
self.setAutoFillBackground(True)
self.resize(400,280)
self.setWindowTitle("QPainter基本绘图")
def paintEvent(self, event):
painter=QPainter(self)
##设置画笔
pen=QPen()
pen.setStyle(Qt.NoPen) #线的类型
painter.setPen(pen)
##绘图
W = self.width()
# 绘图区宽度
H = self.height()
# 绘图区高度
rect=QRect(W/4,H/4,W/2,H/2)
linearGrad=QLinearGradient(rect.left(),rect.top(),rect.right(),rect.top())
linearGrad.setColorAt(0,Qt.blue)#起点颜色
linearGrad.setColorAt(0.5, Qt.white) # 中间点颜色
linearGrad.setColorAt(1, Qt.blue) # 终点颜色
painter.setBrush(linearGrad)
painter.drawRect(rect)
if __name__ == "__main__": ##用于当前窗体测试
app=QApplication(sys.argv) #创建GUI应用程序
form=QmyWidget() #创建窗体
form.show()
sys.exit(app.exec_())
生成如图8-7(b)所示的辐射形渐变填充效果的代码如下:
import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)
class QmyWidget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
self.setAutoFillBackground(True)
self.resize(400,280)
self.setWindowTitle("QPainter基本绘图")
def paintEvent(self, event):
painter=QPainter(self)
##设置画笔
pen=QPen()
pen.setStyle(Qt.NoPen) #线的类型
painter.setPen(pen)
##绘图
W = self.width()
# 绘图区宽度
H = self.height()
# 绘图区高度
radialGrad=QRadialGradient(W/2,H/2,W/3,W/2,H/2)
radialGrad.setColorAt(0, Qt.white)
radialGrad.setColorAt(1, Qt.blue)
painter.setBrush(radialGrad)
rect=QRect(W/4,H/4,W/2,H/2)
painter.drawRect(rect)
if __name__ == "__main__": ##用于当前窗体测试
app=QApplication(sys.argv) #创建GUI应用程序
form=QmyWidget() #创建窗体
form.show()
sys.exit(app.exec_())
import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)
class QmyWidget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
self.setAutoFillBackground(True)
self.resize(400,280)
self.setWindowTitle("QPainter基本绘图")
def paintEvent(self, event):
painter=QPainter(self)
##设置画笔
pen=QPen()
pen.setStyle(Qt.NoPen) #线的类型
painter.setPen(pen)
##绘图
W = self.width()
# 绘图区宽度
H = self.height()
# 绘图区高度
radialGrad=QRadialGradient(W/2,H/2,W/2,3*W/4,H/2)
radialGrad.setColorAt(0, Qt.yellow)
radialGrad.setColorAt(0.8, Qt.blue)
painter.setBrush(radialGrad)
rect=QRect(W/4,H/4,W/2,H/2)
painter.drawEllipse(rect)
if __name__ == "__main__": ##用于当前窗体测试
app=QApplication(sys.argv) #创建GUI应用程序
form=QmyWidget() #创建窗体
form.show()
sys.exit(app.exec_())
效果图:
import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)
class QmyWidget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
self.setAutoFillBackground(True)
self.resize(400,280)
self.setWindowTitle("QPainter基本绘图")
def paintEvent(self, event):
painter=QPainter(self)
##设置画笔
pen=QPen()
pen.setStyle(Qt.NoPen) #线的类型
painter.setPen(pen)
##绘图
W = self.width()
# 绘图区宽度
H = self.height()
# 绘图区高度
radialGrad=QRadialGradient(W/2,H/2,W/8,W/2,H/2)
radialGrad.setColorAt(0, Qt.yellow)
radialGrad.setColorAt(1, Qt.blue)
##延展模式PadSpread、RepeatSpread、ReflectSpread
radialGrad.setSpread(QGradient.ReflectSpread)
painter.setBrush(radialGrad)
painter.drawRect(self.rect())
if __name__ == "__main__": ##用于当前窗体测试
app=QApplication(sys.argv) #创建GUI应用程序
form=QmyWidget() #创建窗体
form.show()
sys.exit(app.exec_())
import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)
class QmyWidget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
self.setAutoFillBackground(True)
self.resize(400,280)
self.setWindowTitle("QPainter基本绘图")
def paintEvent(self, event):
painter=QPainter(self)
##设置画笔
pen=QPen()
pen.setStyle(Qt.NoPen) #线的类型
painter.setPen(pen)
##绘图
W = self.width()
# 绘图区宽度
H = self.height()
# 绘图区高度
radialGrad=QRadialGradient(W/2,H/2,W/8,W/2,H/2)
radialGrad.setColorAt(0, Qt.yellow)
radialGrad.setColorAt(1, Qt.blue)
##延展模式PadSpread、RepeatSpread、ReflectSpread
radialGrad.setSpread(QGradient.PadSpread)
painter.setBrush(radialGrad)
painter.drawRect(self.rect())
if __name__ == "__main__": ##用于当前窗体测试
app=QApplication(sys.argv) #创建GUI应用程序
form=QmyWidget() #创建窗体
form.show()
sys.exit(app.exec_())
import sys
from PyQt5.QtWidgets import QApplication,QWidget
from PyQt5.QtCore import Qt,QRect,QLine,QPoint,QRectF
from PyQt5.QtGui import (QPainter,QPen,QBrush,QPalette,QFont,QImage,QPainterPath,
QPolygon,QPixmap,QRadialGradient,QGradient,QLinearGradient,QConicalGradient)
class QmyWidget(QWidget):
def __init__(self,parent=None):
super().__init__(parent)
self.setPalette(QPalette(Qt.white)) #设置窗口背景颜色为白色
self.setAutoFillBackground(True)
self.resize(400,280)
self.setWindowTitle("QPainter基本绘图")
def paintEvent(self, event):
painter=QPainter(self)
##设置画笔
pen=QPen()
pen.setStyle(Qt.NoPen) #线的类型
painter.setPen(pen)
##绘图
W = self.width()
# 绘图区宽度
H = self.height()
# 绘图区高度
radialGrad=QRadialGradient(W/2,H/2,W/8,W/2,H/2)
radialGrad.setColorAt(0, Qt.yellow)
radialGrad.setColorAt(1, Qt.blue)
##延展模式PadSpread、RepeatSpread、ReflectSpread
radialGrad.setSpread(QGradient.RepeatSpread)
painter.setBrush(radialGrad)
painter.drawRect(self.rect())
if __name__ == "__main__": ##用于当前窗体测试
app=QApplication(sys.argv) #创建GUI应用程序
form=QmyWidget() #创建窗体
form.show()
sys.exit(app.exec_())