1#!/usr/bin/env python 2 3 4############################################################################# 5## 6## Copyright (C) 2013 Riverbank Computing Limited. 7## Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies). 8## All rights reserved. 9## 10## This file is part of the examples of PyQt. 11## 12## $QT_BEGIN_LICENSE:BSD$ 13## You may use this file under the terms of the BSD license as follows: 14## 15## "Redistribution and use in source and binary forms, with or without 16## modification, are permitted provided that the following conditions are 17## met: 18## * Redistributions of source code must retain the above copyright 19## notice, this list of conditions and the following disclaimer. 20## * Redistributions in binary form must reproduce the above copyright 21## notice, this list of conditions and the following disclaimer in 22## the documentation and/or other materials provided with the 23## distribution. 24## * Neither the name of Nokia Corporation and its Subsidiary(-ies) nor 25## the names of its contributors may be used to endorse or promote 26## products derived from this software without specific prior written 27## permission. 28## 29## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 30## "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 31## LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 32## A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 33## OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 34## SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 35## LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 36## DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 37## THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 38## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 39## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE." 40## $QT_END_LICENSE$ 41## 42############################################################################# 43 44 45from math import cos, pi, sin 46 47from PyQt5.QtCore import QSize, Qt 48from PyQt5.QtGui import (QBrush, QColor, QFont, QLinearGradient, QPainter, 49 QPainterPath, QPalette, QPen) 50from PyQt5.QtWidgets import (QApplication, QComboBox, QGridLayout, QLabel, 51 QSizePolicy, QSpinBox, QWidget) 52 53 54class RenderArea(QWidget): 55 def __init__(self, path, parent=None): 56 super(RenderArea, self).__init__(parent) 57 58 self.path = path 59 60 self.penWidth = 1 61 self.rotationAngle = 0 62 self.setBackgroundRole(QPalette.Base) 63 64 def minimumSizeHint(self): 65 return QSize(50, 50) 66 67 def sizeHint(self): 68 return QSize(100, 100) 69 70 def setFillRule(self, rule): 71 self.path.setFillRule(rule) 72 self.update() 73 74 def setFillGradient(self, color1, color2): 75 self.fillColor1 = color1 76 self.fillColor2 = color2 77 self.update() 78 79 def setPenWidth(self, width): 80 self.penWidth = width 81 self.update() 82 83 def setPenColor(self, color): 84 self.penColor = color 85 self.update() 86 87 def setRotationAngle(self, degrees): 88 self.rotationAngle = degrees 89 self.update() 90 91 def paintEvent(self, event): 92 painter = QPainter(self) 93 painter.setRenderHint(QPainter.Antialiasing) 94 painter.scale(self.width() / 100.0, self.height() / 100.0) 95 painter.translate(50.0, 50.0) 96 painter.rotate(-self.rotationAngle) 97 painter.translate(-50.0, -50.0) 98 99 painter.setPen( 100 QPen(self.penColor, self.penWidth, Qt.SolidLine, Qt.RoundCap, 101 Qt.RoundJoin)) 102 gradient = QLinearGradient(0, 0, 0, 100) 103 gradient.setColorAt(0.0, self.fillColor1) 104 gradient.setColorAt(1.0, self.fillColor2) 105 painter.setBrush(QBrush(gradient)) 106 painter.drawPath(self.path) 107 108 109class Window(QWidget): 110 NumRenderAreas = 9 111 112 def __init__(self): 113 super(Window, self).__init__() 114 115 rectPath = QPainterPath() 116 rectPath.moveTo(20.0, 30.0) 117 rectPath.lineTo(80.0, 30.0) 118 rectPath.lineTo(80.0, 70.0) 119 rectPath.lineTo(20.0, 70.0) 120 rectPath.closeSubpath() 121 122 roundRectPath = QPainterPath() 123 roundRectPath.moveTo(80.0, 35.0) 124 roundRectPath.arcTo(70.0, 30.0, 10.0, 10.0, 0.0, 90.0) 125 roundRectPath.lineTo(25.0, 30.0) 126 roundRectPath.arcTo(20.0, 30.0, 10.0, 10.0, 90.0, 90.0) 127 roundRectPath.lineTo(20.0, 65.0) 128 roundRectPath.arcTo(20.0, 60.0, 10.0, 10.0, 180.0, 90.0) 129 roundRectPath.lineTo(75.0, 70.0) 130 roundRectPath.arcTo(70.0, 60.0, 10.0, 10.0, 270.0, 90.0) 131 roundRectPath.closeSubpath() 132 133 ellipsePath = QPainterPath() 134 ellipsePath.moveTo(80.0, 50.0) 135 ellipsePath.arcTo(20.0, 30.0, 60.0, 40.0, 0.0, 360.0) 136 137 piePath = QPainterPath() 138 piePath.moveTo(50.0, 50.0) 139 piePath.lineTo(65.0, 32.6795) 140 piePath.arcTo(20.0, 30.0, 60.0, 40.0, 60.0, 240.0) 141 piePath.closeSubpath() 142 143 polygonPath = QPainterPath() 144 polygonPath.moveTo(10.0, 80.0) 145 polygonPath.lineTo(20.0, 10.0) 146 polygonPath.lineTo(80.0, 30.0) 147 polygonPath.lineTo(90.0, 70.0) 148 polygonPath.closeSubpath() 149 150 groupPath = QPainterPath() 151 groupPath.moveTo(60.0, 40.0) 152 groupPath.arcTo(20.0, 20.0, 40.0, 40.0, 0.0, 360.0) 153 groupPath.moveTo(40.0, 40.0) 154 groupPath.lineTo(40.0, 80.0) 155 groupPath.lineTo(80.0, 80.0) 156 groupPath.lineTo(80.0, 40.0) 157 groupPath.closeSubpath() 158 159 textPath = QPainterPath() 160 timesFont = QFont('Times', 50) 161 timesFont.setStyleStrategy(QFont.ForceOutline) 162 textPath.addText(10, 70, timesFont, "Qt") 163 164 bezierPath = QPainterPath() 165 bezierPath.moveTo(20, 30) 166 bezierPath.cubicTo(80, 0, 50, 50, 80, 80) 167 168 starPath = QPainterPath() 169 starPath.moveTo(90, 50) 170 for i in range(1, 5): 171 starPath.lineTo(50 + 40 * cos(0.8 * i * pi), 172 50 + 40 * sin(0.8 * i * pi)) 173 starPath.closeSubpath() 174 175 self.renderAreas = [RenderArea(rectPath), RenderArea(roundRectPath), 176 RenderArea(ellipsePath), RenderArea(piePath), 177 RenderArea(polygonPath), RenderArea(groupPath), 178 RenderArea(textPath), RenderArea(bezierPath), 179 RenderArea(starPath)] 180 assert len(self.renderAreas) == 9 181 182 self.fillRuleComboBox = QComboBox() 183 self.fillRuleComboBox.addItem("Odd Even", Qt.OddEvenFill) 184 self.fillRuleComboBox.addItem("Winding", Qt.WindingFill) 185 186 fillRuleLabel = QLabel("Fill &Rule:") 187 fillRuleLabel.setBuddy(self.fillRuleComboBox) 188 189 self.fillColor1ComboBox = QComboBox() 190 self.populateWithColors(self.fillColor1ComboBox) 191 self.fillColor1ComboBox.setCurrentIndex( 192 self.fillColor1ComboBox.findText("mediumslateblue")) 193 194 self.fillColor2ComboBox = QComboBox() 195 self.populateWithColors(self.fillColor2ComboBox) 196 self.fillColor2ComboBox.setCurrentIndex( 197 self.fillColor2ComboBox.findText("cornsilk")) 198 199 fillGradientLabel = QLabel("&Fill Gradient:") 200 fillGradientLabel.setBuddy(self.fillColor1ComboBox) 201 202 fillToLabel = QLabel("to") 203 fillToLabel.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed) 204 205 self.penWidthSpinBox = QSpinBox() 206 self.penWidthSpinBox.setRange(0, 20) 207 208 penWidthLabel = QLabel("&Pen Width:") 209 penWidthLabel.setBuddy(self.penWidthSpinBox) 210 211 self.penColorComboBox = QComboBox() 212 self.populateWithColors(self.penColorComboBox) 213 self.penColorComboBox.setCurrentIndex( 214 self.penColorComboBox.findText('darkslateblue')) 215 216 penColorLabel = QLabel("Pen &Color:") 217 penColorLabel.setBuddy(self.penColorComboBox) 218 219 self.rotationAngleSpinBox = QSpinBox() 220 self.rotationAngleSpinBox.setRange(0, 359) 221 self.rotationAngleSpinBox.setWrapping(True) 222 self.rotationAngleSpinBox.setSuffix(u'\N{DEGREE SIGN}') 223 224 rotationAngleLabel = QLabel("&Rotation Angle:") 225 rotationAngleLabel.setBuddy(self.rotationAngleSpinBox) 226 227 self.fillRuleComboBox.activated.connect(self.fillRuleChanged) 228 self.fillColor1ComboBox.activated.connect(self.fillGradientChanged) 229 self.fillColor2ComboBox.activated.connect(self.fillGradientChanged) 230 self.penColorComboBox.activated.connect(self.penColorChanged) 231 232 for i in range(Window.NumRenderAreas): 233 self.penWidthSpinBox.valueChanged.connect(self.renderAreas[i].setPenWidth) 234 self.rotationAngleSpinBox.valueChanged.connect(self.renderAreas[i].setRotationAngle) 235 236 topLayout = QGridLayout() 237 for i in range(Window.NumRenderAreas): 238 topLayout.addWidget(self.renderAreas[i], i / 3, i % 3) 239 240 mainLayout = QGridLayout() 241 mainLayout.addLayout(topLayout, 0, 0, 1, 4) 242 mainLayout.addWidget(fillRuleLabel, 1, 0) 243 mainLayout.addWidget(self.fillRuleComboBox, 1, 1, 1, 3) 244 mainLayout.addWidget(fillGradientLabel, 2, 0) 245 mainLayout.addWidget(self.fillColor1ComboBox, 2, 1) 246 mainLayout.addWidget(fillToLabel, 2, 2) 247 mainLayout.addWidget(self.fillColor2ComboBox, 2, 3) 248 mainLayout.addWidget(penWidthLabel, 3, 0) 249 mainLayout.addWidget(self.penWidthSpinBox, 3, 1, 1, 3) 250 mainLayout.addWidget(penColorLabel, 4, 0) 251 mainLayout.addWidget(self.penColorComboBox, 4, 1, 1, 3) 252 mainLayout.addWidget(rotationAngleLabel, 5, 0) 253 mainLayout.addWidget(self.rotationAngleSpinBox, 5, 1, 1, 3) 254 self.setLayout(mainLayout) 255 256 self.fillRuleChanged() 257 self.fillGradientChanged() 258 self.penColorChanged() 259 self.penWidthSpinBox.setValue(2) 260 261 self.setWindowTitle("Painter Paths") 262 263 def fillRuleChanged(self): 264 rule = Qt.FillRule(self.currentItemData(self.fillRuleComboBox)) 265 266 for i in range(Window.NumRenderAreas): 267 self.renderAreas[i].setFillRule(rule) 268 269 def fillGradientChanged(self): 270 color1 = QColor(self.currentItemData(self.fillColor1ComboBox)) 271 color2 = QColor(self.currentItemData(self.fillColor2ComboBox)) 272 273 for i in range(Window.NumRenderAreas): 274 self.renderAreas[i].setFillGradient(color1, color2) 275 276 def penColorChanged(self): 277 color = QColor(self.currentItemData(self.penColorComboBox)) 278 279 for i in range(Window.NumRenderAreas): 280 self.renderAreas[i].setPenColor(color) 281 282 def populateWithColors(self, comboBox): 283 colorNames = QColor.colorNames() 284 for name in colorNames: 285 comboBox.addItem(name, name) 286 287 def currentItemData(self, comboBox): 288 return comboBox.itemData(comboBox.currentIndex()) 289 290 291if __name__ == '__main__': 292 293 import sys 294 295 app = QApplication(sys.argv) 296 window = Window() 297 window.show() 298 sys.exit(app.exec_()) 299