[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_())