[Qt扒手2] PyQt5 路径绘画例子

简介: 【说明】 此例扒自 Qt 官网,原例是 C++ 代码,我把它改写成了 Python + PyQt5 版本。 有了前一个例子的成功,这个例子改写的非常之快。记得第一个例子花了我几天的时间,而这个例子只花了半个小时。

 

【说明】

此例扒自 Qt 官网,原例是 C++ 代码,我把它改写成了 Python + PyQt5 版本。

有了前一个例子的成功,这个例子改写的非常之快。记得第一个例子花了我几天的时间,而这个例子只花了半个小时。

当然,过程中也遇到了一些新问题,比如 renderAreas 被定义成 QList类,而QList类的迭代,调试了几次都报错。没有办法,干脆把renderAreas 修改定义为Python的 list 类型,然后就OK了!!

 

本例基于: Win7 + Python 3.4 + PyQt5

 

【效果图】

 

 

对比原C++界面:

 

【源代码】

  1 # File: Painter Paths Example.py
  2 # Author: Robin
  3 # Date: 2015.2.9
  4 # C++: http://doc.qt.io/qt-5/qtwidgets-painting-painterpaths-example.html
  5 
  6 import math
  7 from PyQt5.QtCore import *
  8 from PyQt5.QtGui import *
  9 from PyQt5.QtWidgets import *
 10 
 11 
 12 class RenderArea(QWidget):
 13     def __init__(self, path, parent=None):
 14         super(RenderArea, self).__init__(parent)
 15         self.penWidth = 1
 16         self.rotationAngle = 0
 17         self.path = path
 18         self.setBackgroundRole(QPalette.Base)
 19         self.setAutoFillBackground(True)
 20         
 21     def minimumSizeHint(self):
 22         return QSize(50, 50)
 23         
 24     def sizeHint(self):
 25         return QSize(100, 100)
 26         
 27     def setFillRule(self, rule):
 28         self.path.setFillRule(rule)
 29         self.update()
 30         
 31     def setFillGradient(self, color1, color2):
 32         self.fillColor1 = color1
 33         self.fillColor2 = color2
 34         self.update()
 35         
 36     def setPenWidth(self, width):
 37         self.penWidth = width
 38         self.update()
 39         
 40     def setPenColor(self, color):
 41         self.penColor = color
 42         self.update()
 43         
 44     def setRotationAngle(self, degrees):
 45         self.rotationAngle = degrees
 46         self.update()
 47         
 48     def paintEvent(self, event):
 49         painter = QPainter(self)
 50         painter.setRenderHint(QPainter.Antialiasing)
 51         painter.scale(self.width() / 100.0, self.height() / 100.0)
 52         painter.translate(50.0, 50.0)
 53         painter.rotate(-self.rotationAngle)
 54         painter.translate(-50.0, -50.0)
 55         painter.setPen(QPen(self.penColor, self.penWidth, Qt.SolidLine, Qt.RoundCap, Qt.RoundJoin))
 56         gradient = QLinearGradient(0, 0, 0, 100)
 57         gradient.setColorAt(0.0, self.fillColor1)
 58         gradient.setColorAt(1.0, self.fillColor2)
 59         painter.setBrush(gradient)
 60         painter.drawPath(self.path)
 61 
 62 
 63 class MyWindow(QWidget):
 64     
 65     def __init__(self):
 66         super(MyWindow, self).__init__() 
 67         #self.setUi()
 68         #self.Pi = 3.1415926
 69         # 矩形路径
 70         self.rectPath = QPainterPath()
 71         self.rectPath.moveTo(20.0, 30.0)
 72         self.rectPath.lineTo(80.0, 30.0)
 73         self.rectPath.lineTo(80.0, 70.0)
 74         self.rectPath.lineTo(20.0, 70.0)
 75         self.rectPath.closeSubpath()
 76         # 圆角矩形路径
 77         self.roundRectPath = QPainterPath()
 78         self.roundRectPath.moveTo(80.0, 35.0)
 79         self.roundRectPath.arcTo(70.0, 30.0, 10.0, 10.0, 0.0, 90.0)
 80         self.roundRectPath.lineTo(25.0, 30.0)
 81         self.roundRectPath.arcTo(20.0, 30.0, 10.0, 10.0, 90.0, 90.0)
 82         self.roundRectPath.lineTo(20.0, 65.0)
 83         self.roundRectPath.arcTo(20.0, 60.0, 10.0, 10.0, 180.0, 90.0)
 84         self.roundRectPath.lineTo(75.0, 70.0)
 85         self.roundRectPath.arcTo(70.0, 60.0, 10.0, 10.0, 270.0, 90.0)
 86         self.roundRectPath.closeSubpath()
 87         # 椭圆路径
 88         self.ellipsePath = QPainterPath()
 89         self.ellipsePath.moveTo(80.0, 50.0)
 90         self.ellipsePath.arcTo(20.0, 30.0, 60.0, 40.0, 0.0, 360.0)
 91         # 饼图路径
 92         self.piePath = QPainterPath()
 93         self.piePath.moveTo(50.0, 50.0)
 94         self.piePath.arcTo(20.0, 30.0, 60.0, 40.0, 60.0, 240.0)
 95         self.piePath.closeSubpath()
 96         # 多边形路径
 97         self.polygonPath = QPainterPath()
 98         self.polygonPath.moveTo(10.0, 80.0)
 99         self.polygonPath.lineTo(20.0, 10.0)
100         self.polygonPath.lineTo(80.0, 30.0)
101         self.polygonPath.lineTo(90.0, 70.0)
102         self.polygonPath.closeSubpath()
103         # 组合路径
104         self.groupPath = QPainterPath()
105         self.groupPath.moveTo(60.0, 40.0)
106         self.groupPath.arcTo(20.0, 20.0, 40.0, 40.0, 0.0, 360.0)
107         self.groupPath.moveTo(40.0, 40.0)
108         self.groupPath.lineTo(40.0, 80.0)
109         self.groupPath.lineTo(80.0, 80.0)
110         self.groupPath.lineTo(80.0, 40.0)
111         self.groupPath.closeSubpath()
112         # 文字路径
113         self.textPath = QPainterPath()
114         self.timesFont = QFont("Times", 50)
115         self.timesFont.setStyleStrategy(QFont.ForceOutline)
116         self.textPath.addText(10, 70, self.timesFont, "Qt")
117         # 贝兹尔路径
118         self.bezierPath = QPainterPath()
119         self.bezierPath.moveTo(20, 30)
120         self.bezierPath.cubicTo(80, 0, 50, 50, 80, 80)
121         
122         self.starPath = QPainterPath()
123         self.starPath.moveTo(90, 50)
124         for i in range(5):
125             self.starPath.lineTo(50 + 40 * math.cos(0.8 * i * math.pi),
126                             50 + 40 * math.sin(0.8 * i * math.pi))
127         self.starPath.closeSubpath()
128         
129         self.renderAreas = []
130         self.renderAreas.append(RenderArea(self.rectPath))
131         self.renderAreas.append(RenderArea(self.roundRectPath))
132         self.renderAreas.append(RenderArea(self.ellipsePath))
133         self.renderAreas.append(RenderArea(self.piePath))
134         self.renderAreas.append(RenderArea(self.polygonPath))
135         self.renderAreas.append(RenderArea(self.groupPath))
136         self.renderAreas.append(RenderArea(self.textPath))
137         self.renderAreas.append(RenderArea(self.bezierPath))
138         self.renderAreas.append(RenderArea(self.starPath))
139         
140     #def setUi(self):    
141         self.fillRuleComboBox = QComboBox()
142         self.fillRuleComboBox.addItem("Odd Even", Qt.OddEvenFill)
143         self.fillRuleComboBox.addItem("Winding", Qt.WindingFill)
144 
145         self.fillRuleLabel = QLabel("Fill &Rule:")
146         self.fillRuleLabel.setBuddy(self.fillRuleComboBox)
147 
148         self.fillColor1ComboBox = QComboBox()
149         self.populateWithColors(self.fillColor1ComboBox)
150         self.fillColor1ComboBox.setCurrentIndex(self.fillColor1ComboBox.findText("mediumslateblue"))
151 
152         self.fillColor2ComboBox = QComboBox()
153         self.populateWithColors(self.fillColor2ComboBox)
154         self.fillColor2ComboBox.setCurrentIndex(self.fillColor2ComboBox.findText("cornsilk"))
155 
156         self.fillGradientLabel = QLabel("&Fill Gradient:")
157         self.fillGradientLabel.setBuddy(self.fillColor1ComboBox)
158 
159         self.fillToLabel = QLabel("to")
160         self.fillToLabel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
161 
162         self.penWidthSpinBox = QSpinBox()
163         self.penWidthSpinBox.setRange(0, 20)
164 
165         self.penWidthLabel = QLabel("&Pen Width:")
166         self.penWidthLabel.setBuddy(self.penWidthSpinBox)
167 
168         self.penColorComboBox = QComboBox()
169         self.populateWithColors(self.penColorComboBox)
170         self.penColorComboBox.setCurrentIndex(self.penColorComboBox.findText("darkslateblue"))
171 
172         self.penColorLabel = QLabel("Pen &Color:")
173         self.penColorLabel.setBuddy(self.penColorComboBox)
174 
175         self.rotationAngleSpinBox = QSpinBox()
176         self.rotationAngleSpinBox.setRange(0, 359)
177         self.rotationAngleSpinBox.setWrapping(True)
178         self.rotationAngleSpinBox.setSuffix("°")
179 
180         self.rotationAngleLabel = QLabel("&Rotation Angle:")
181         self.rotationAngleLabel.setBuddy(self.rotationAngleSpinBox)
182 
183         self.fillRuleComboBox.activated.connect(self.fillRuleChanged)
184         self.fillColor1ComboBox.activated.connect(self.fillGradientChanged)
185         self.fillColor2ComboBox.activated.connect(self.fillGradientChanged)
186         self.penColorComboBox.activated.connect(self.penColorChanged)
187 
188         for it in self.renderAreas: 
189             self.penWidthSpinBox.valueChanged.connect(it.setPenWidth)
190             self.rotationAngleSpinBox.valueChanged.connect(it.setRotationAngle)
191 
192         
193         topLayout = QGridLayout()
194 
195         i = 0
196         for i, it in enumerate(self.renderAreas):
197             topLayout.addWidget(it, i // 3, i % 3)
198             
199 
200         mainLayout = QGridLayout()
201         mainLayout.addLayout(topLayout, 0, 0, 1, 4)
202         mainLayout.addWidget(self.fillRuleLabel, 1, 0)
203         mainLayout.addWidget(self.fillRuleComboBox, 1, 1, 1, 3)
204         mainLayout.addWidget(self.fillGradientLabel, 2, 0)
205         mainLayout.addWidget(self.fillColor1ComboBox, 2, 1)
206         mainLayout.addWidget(self.fillToLabel, 2, 2)
207         mainLayout.addWidget(self.fillColor2ComboBox, 2, 3)
208         mainLayout.addWidget(self.penWidthLabel, 3, 0)
209         mainLayout.addWidget(self.penWidthSpinBox, 3, 1, 1, 3)
210         mainLayout.addWidget(self.penColorLabel, 4, 0)
211         mainLayout.addWidget(self.penColorComboBox, 4, 1, 1, 3)
212         mainLayout.addWidget(self.rotationAngleLabel, 5, 0)
213         mainLayout.addWidget(self.rotationAngleSpinBox, 5, 1, 1, 3)
214         self.setLayout(mainLayout)
215 
216         self.fillRuleChanged()
217         self.fillGradientChanged()
218         self.penColorChanged()
219         self.penWidthSpinBox.setValue(2)
220 
221         self.setWindowTitle("Painter Paths")
222 
223     def fillRuleChanged(self):
224         rule = self.currentItemData(self.fillRuleComboBox)
225         for it in self.renderAreas:
226             it.setFillRule(rule)
227 
228     def fillGradientChanged(self):
229         color1 = self.currentItemData(self.fillColor1ComboBox)
230         color2 = self.currentItemData(self.fillColor2ComboBox)
231         for it in self.renderAreas:
232             it.setFillGradient(color1, color2)
233 
234     def penColorChanged(self):
235         color = self.currentItemData(self.penColorComboBox)
236         for it in self.renderAreas:
237             it.setPenColor(color)
238     
239     @staticmethod
240     def populateWithColors(comboBox):
241         colorNames = QColor.colorNames()
242         for name in colorNames:
243             comboBox.addItem(name, QColor(name))
244     
245     @staticmethod
246     def currentItemData(comboBox):
247         return comboBox.itemData(comboBox.currentIndex(),Qt.UserRole)
248 
249 
250 if __name__ == "__main__":
251     import sys
252     app = QApplication(sys.argv)
253     win = MyWindow()
254     win.show()
255     sys.exit(app.exec_())
View Code

 

目录
相关文章
|
SQL 关系型数据库 分布式数据库
PolarDB常见问题之修改root密码失败如何解决
PolarDB是阿里云推出的下一代关系型数据库,具有高性能、高可用性和弹性伸缩能力,适用于大规模数据处理场景。本汇总囊括了PolarDB使用中用户可能遭遇的一系列常见问题及解答,旨在为数据库管理员和开发者提供全面的问题指导,确保数据库平稳运行和优化使用体验。
|
Java Android开发
Android面试题经典之Glide取消加载以及线程池优化
Glide通过生命周期管理在`onStop`时暂停请求,`onDestroy`时取消请求,减少资源浪费。在`EngineJob`和`DecodeJob`中使用`cancel`方法标记任务并中断数据获取。当网络请求被取消时,`HttpUrlFetcher`的`cancel`方法设置标志,之后的数据获取会返回`null`,中断加载流程。Glide还使用定制的线程池,如AnimationExecutor、diskCacheExecutor、sourceExecutor和newUnlimitedSourceExecutor,其中某些禁止网络访问,并根据CPU核心数动态调整线程数。
331 2
|
7月前
|
人工智能 数据可视化 Linux
【保姆级教程】3步搞定DeepSeek本地部署
DeepSeek在2025年春节期间突然爆火出圈。在目前DeepSeek的网站中,极不稳定,总是服务器繁忙,这时候本地部署就可以有效规避问题。本文以最浅显易懂的方式带读者一起完成DeepSeek-r1大模型的本地部署。
4931 8
|
11月前
|
缓存 网络协议 算法
TCP的滑动窗口与拥塞控制
【10月更文挑战第7天】这段内容详细介绍了TCP协议中确保数据包可靠传输的机制,包括使用ID确保顺序性与累计确认、发送端与接收端的缓存管理、超时重传策略及自适应重传算法,以及拥塞控制机制如慢启动、拥塞避免和快速重传。
|
Linux Windows
FinalShell连接Linux虚拟机报错java.net.ConnectException: Connection timed out: connect(亲测有效)
FinalShell连接Linux虚拟机报错java.net.ConnectException: Connection timed out: connect(亲测有效)
3120 0
|
12月前
|
缓存 前端开发 JavaScript
探索现代前端框架与工具链
探索现代前端框架与工具链
147 0
|
SQL 缓存 Java
MyBatis原理分析之获取SqlSessionFactory
MyBatis原理分析之获取SqlSessionFactory
531 0
|
JSON 数据格式 Python
优秀!Python版按键精灵,电脑鼠标、键盘手势动作一键复制操作,优雅极了!
优秀!Python版按键精灵,电脑鼠标、键盘手势动作一键复制操作,优雅极了!
651 0
|
Python
Pycharm没有报错提示(误触ignore)的解决方案
Pycharm没有报错提示(误触ignore)的解决方案
1662 0
|
API
XGBoost超参数调优指南
本文将详细解释XGBoost中十个最常用超参数的介绍,功能和值范围,及如何使用Optuna进行超参数调优。
826 1