Article Outline
Python pyqt (gui) example 'bubbleswidget'
Modules used in program:
import random
bubbleswidget
Python pyqt example: bubbleswidget
#!/usr/bin/env python
"""
bubbleswidget.py
A PyQt custom widget example for Qt Designer.
Copyright (C) 2006 David Boddie <[email protected]>
Copyright (C) 2005-2006 Trolltech ASA. All rights reserved.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
"""
import random
from PyQt5.QtCore import (pyqtProperty, pyqtSignal, pyqtSlot, QPointF, QRectF,
QSize, QSizeF, Qt, QTimer)
from PyQt5.QtGui import QBrush, QColor, QPainter, QPen, QRadialGradient
from PyQt5.QtWidgets import QApplication, QWidget
class BaseClass(QWidget):
"""BaseClass(QWidget)
Provides a base custom widget class to show that properties implemented
in Python can be inherited and shown as belonging to distinct classes
in Qt Designer's Property Editor.
"""
def __init__(self, parent=None):
super(BaseClass, self).__init__(parent)
self.resetAuthor()
# Define getter, setter and resetter methods for the author property.
def getAuthor(self):
return self._author
def setAuthor(self, name):
self._author = name
def resetAuthor(self):
self._author = "David Boddie"
author = pyqtProperty(str, getAuthor, setAuthor, resetAuthor)
class Bubble:
"""Bubble
Provides a class to represent individual bubbles in a BubblesWidget.
Each Bubble instance can render itself onto a paint device using a
QPainter passed to its drawBubble() method.
"""
def __init__(self, position, radius, speed, innerColor, outerColor):
self.position = position
self.radius = radius
self.speed = speed
self.innerColor = innerColor
self.outerColor = outerColor
self.updateBrush()
def updateBrush(self):
gradient = QRadialGradient(
QPointF(self.radius, self.radius), self.radius,
QPointF(self.radius*0.5, self.radius*0.5))
gradient.setColorAt(0, QColor(255, 255, 255, 255))
gradient.setColorAt(0.25, self.innerColor)
gradient.setColorAt(1, self.outerColor)
self.brush = QBrush(gradient)
def drawBubble(self, painter):
painter.save()
painter.translate(self.position.x() - self.radius,
self.position.y() - self.radius)
painter.setBrush(self.brush)
painter.drawEllipse(0.0, 0.0, 2*self.radius, 2*self.radius)
painter.restore()
class BubblesWidget(BaseClass):
"""BubblesWidget(BaseClass)
Provides a custom widget that shows a number of rising bubbles.
Various properties are defined so that the user can customize the
appearance of the widget, and change the number and behaviour of the
bubbles shown.
"""
# We define two signals that are used to indicate changes to the status
# of the widget.
bubbleLeft = pyqtSignal()
bubblesRemaining = pyqtSignal(int)
def __init__(self, parent=None):
super(BubblesWidget, self).__init__(parent)
self.pen = QPen(QColor("#cccccc"))
self.bubbles = []
self.backgroundColor1 = self.randomColor()
self.backgroundColor2 = self.randomColor().darker(150)
self.newBubble = None
random.seed()
self.animation_timer = QTimer(self)
self.animation_timer.setSingleShot(False)
self.animation_timer.timeout.connect(self.animate)
self.animation_timer.start(25)
self.bubbleTimer = QTimer()
self.bubbleTimer.setSingleShot(False)
self.bubbleTimer.timeout.connect(self.expandBubble)
self.setMouseTracking(True)
self.setMinimumSize(QSize(200, 200))
self.setWindowTitle("Bubble Maker")
def paintEvent(self, event):
background = QRadialGradient(QPointF(self.rect().topLeft()), 500,
QPointF(self.rect().bottomRight()))
background.setColorAt(0, self.backgroundColor1)
background.setColorAt(1, self.backgroundColor2)
painter = QPainter()
painter.begin(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.fillRect(event.rect(), QBrush(background))
painter.setPen(self.pen)
for bubble in self.bubbles:
if QRectF(bubble.position - QPointF(bubble.radius, bubble.radius),
QSizeF(2*bubble.radius, 2*bubble.radius)).intersects(QRectF(event.rect())):
bubble.drawBubble(painter)
if self.newBubble:
self.newBubble.drawBubble(painter)
painter.end()
def mousePressEvent(self, event):
if event.button() == Qt.LeftButton and self.newBubble is None:
self.newBubble = Bubble(QPointF(event.pos()), 4.0,
1.0 + random.random() * 7,
self.randomColor(), self.randomColor())
self.bubbleTimer.start(50)
event.accept()
def mouseMoveEvent(self, event):
if self.newBubble:
self.update(
QRectF(self.newBubble.position - \
QPointF(self.newBubble.radius + 1, self.newBubble.radius + 1),
QSizeF(2*self.newBubble.radius + 2, 2*self.newBubble.radius + 2)).toRect()
)
self.newBubble.position = QPointF(event.pos())
self.update(
QRectF(self.newBubble.position - \
QPointF(self.newBubble.radius + 1, self.newBubble.radius + 1),
QSizeF(2*self.newBubble.radius + 2, 2*self.newBubble.radius + 2)).toRect()
)
event.accept()
def mouseReleaseEvent(self, event):
if self.newBubble:
self.bubbles.append(self.newBubble)
self.newBubble = None
self.bubbleTimer.stop()
self.bubblesRemaining.emit(len(self.bubbles))
event.accept()
def expandBubble(self):
if self.newBubble:
self.newBubble.radius = min(self.newBubble.radius + 4.0,
self.width()/8.0, self.height()/8.0)
self.update(
QRectF(self.newBubble.position - \
QPointF(self.newBubble.radius + 1, self.newBubble.radius + 1),
QSizeF(2*self.newBubble.radius + 2, 2*self.newBubble.radius + 2)).toRect()
)
self.newBubble.updateBrush()
def randomColor(self):
red = 205 + random.random() * 50
green = 205 + random.random() * 50
blue = 205 + random.random() * 50
alpha = 91 + random.random() * 100
return QColor(red, green, blue, alpha)
def animate(self):
bubbles = []
left = False
for bubble in self.bubbles:
bubble.position = bubble.position + QPointF(0, -bubble.speed)
self.update(
QRectF(bubble.position - QPointF(bubble.radius + 1,
bubble.radius + 1),
QSizeF(2*bubble.radius + 2, 2*bubble.radius + 2 + bubble.speed)).toRect())
if bubble.position.y() + bubble.radius > 0:
bubbles.append(bubble)
else:
self.bubbleLeft.emit()
left = True
if self.newBubble:
self.update(
QRectF(self.newBubble.position - QPointF(
self.newBubble.radius + 1,
self.newBubble.radius + 1),
QSizeF(2*self.newBubble.radius + 2, 2*self.newBubble.radius + 2)).toRect())
self.bubbles = bubbles
if left:
self.bubblesRemaining.emit(len(self.bubbles))
def sizeHint(self):
return QSize(200, 200)
# We provide getter and setter methods for the numberOfBubbles property.
def getBubbles(self):
return len(self.bubbles)
# The setBubbles() method can also be used as a slot.
@pyqtSlot(int)
def setBubbles(self, value):
value = max(0, value)
while len(self.bubbles) < value:
newBubble = Bubble(QPointF(random.random() * self.width(),
random.random() * self.height()),
4.0 + random.random() * 20,
1.0 + random.random() * 7,
self.randomColor(), self.randomColor())
newBubble.updateBrush()
self.bubbles.append(newBubble)
self.bubbles = self.bubbles[:value]
self.bubblesRemaining.emit(value)
self.update()
numberOfBubbles = pyqtProperty(int, getBubbles, setBubbles)
# We provide getter and setter methods for the color1 and color2
# properties. The red, green and blue components for the QColor
# values stored in these properties can be edited individually in
# Qt Designer.
def getColor1(self):
return self.backgroundColor1
def setColor1(self, value):
self.backgroundColor1 = QColor(value)
self.update()
color1 = pyqtProperty(QColor, getColor1, setColor1)
def getColor2(self):
return self.backgroundColor2
def setColor2(self, value):
self.backgroundColor2 = QColor(value)
self.update()
color2 = pyqtProperty(QColor, getColor2, setColor2)
# The stop() and start() slots provide simple control over the animation
# of the bubbles in the widget.
@pyqtSlot()
def stop(self):
self.animation_timer.stop()
@pyqtSlot()
def start(self):
self.animation_timer.start(25)
if __name__ == "__main__":
import sys
app = QApplication(sys.argv)
widget = BubblesWidget()
widget.show()
sys.exit(app.exec_())
Useful links
- Learn PyQt: https://pythonbasics.org/pyqt-hello-world/
- Install PyQt: https://pythonbasics.org/install-pyqt/