[Qt扒手2] 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

 

posted @ 2015-02-09 14:53  罗兵  阅读(2090)  评论(0编辑  收藏  举报