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 PyQt5.QtCore import (QAbstractTransition, QEasingCurve, QEvent, 46 QParallelAnimationGroup, QPropertyAnimation, qrand, QRect, 47 QSequentialAnimationGroup, qsrand, QState, QStateMachine, Qt, QTime, 48 QTimer) 49from PyQt5.QtWidgets import (QApplication, QGraphicsScene, QGraphicsView, 50 QGraphicsWidget) 51 52 53class StateSwitchEvent(QEvent): 54 StateSwitchType = QEvent.User + 256 55 56 def __init__(self, rand=0): 57 super(StateSwitchEvent, self).__init__(StateSwitchEvent.StateSwitchType) 58 59 self.m_rand = rand 60 61 def rand(self): 62 return self.m_rand 63 64 65class QGraphicsRectWidget(QGraphicsWidget): 66 def paint(self, painter, option, widget): 67 painter.fillRect(self.rect(), Qt.blue) 68 69 70class StateSwitchTransition(QAbstractTransition): 71 def __init__(self, rand): 72 super(StateSwitchTransition, self).__init__() 73 74 self.m_rand = rand 75 76 def eventTest(self, event): 77 return (event.type() == StateSwitchEvent.StateSwitchType and 78 event.rand() == self.m_rand) 79 80 def onTransition(self, event): 81 pass 82 83 84class StateSwitcher(QState): 85 def __init__(self, machine): 86 super(StateSwitcher, self).__init__(machine) 87 88 self.m_stateCount = 0 89 self.m_lastIndex = 0 90 91 def onEntry(self, event): 92 n = qrand() % self.m_stateCount + 1 93 while n == self.m_lastIndex: 94 n = qrand() % self.m_stateCount + 1 95 96 self.m_lastIndex = n 97 self.machine().postEvent(StateSwitchEvent(n)) 98 99 def onExit(self, event): 100 pass 101 102 def addState(self, state, animation): 103 self.m_stateCount += 1 104 trans = StateSwitchTransition(self.m_stateCount) 105 trans.setTargetState(state) 106 self.addTransition(trans) 107 trans.addAnimation(animation) 108 109 110def createGeometryState(w1, rect1, w2, rect2, w3, rect3, w4, rect4, parent): 111 result = QState(parent) 112 113 result.assignProperty(w1, 'geometry', rect1) 114 result.assignProperty(w1, 'geometry', rect1) 115 result.assignProperty(w2, 'geometry', rect2) 116 result.assignProperty(w3, 'geometry', rect3) 117 result.assignProperty(w4, 'geometry', rect4) 118 119 return result 120 121 122if __name__ == '__main__': 123 124 import sys 125 126 app = QApplication(sys.argv) 127 128 button1 = QGraphicsRectWidget() 129 button2 = QGraphicsRectWidget() 130 button3 = QGraphicsRectWidget() 131 button4 = QGraphicsRectWidget() 132 button2.setZValue(1) 133 button3.setZValue(2) 134 button4.setZValue(3) 135 136 scene = QGraphicsScene(0, 0, 300, 300) 137 scene.setBackgroundBrush(Qt.black) 138 scene.addItem(button1) 139 scene.addItem(button2) 140 scene.addItem(button3) 141 scene.addItem(button4) 142 143 window = QGraphicsView(scene) 144 window.setFrameStyle(0) 145 window.setAlignment(Qt.AlignLeft | Qt.AlignTop) 146 window.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 147 window.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff) 148 149 machine = QStateMachine() 150 151 group = QState() 152 timer = QTimer() 153 timer.setInterval(1250) 154 timer.setSingleShot(True) 155 group.entered.connect(timer.start) 156 157 state1 = createGeometryState(button1, QRect(100, 0, 50, 50), button2, 158 QRect(150, 0, 50, 50), button3, QRect(200, 0, 50, 50), button4, 159 QRect(250, 0, 50, 50), group) 160 161 state2 = createGeometryState(button1, QRect(250, 100, 50, 50), button2, 162 QRect(250, 150, 50, 50), button3, QRect(250, 200, 50, 50), button4, 163 QRect(250, 250, 50, 50), group) 164 165 state3 = createGeometryState(button1, QRect(150, 250, 50, 50), button2, 166 QRect(100, 250, 50, 50), button3, QRect(50, 250, 50, 50), button4, 167 QRect(0, 250, 50, 50), group) 168 169 state4 = createGeometryState(button1, QRect(0, 150, 50, 50), button2, 170 QRect(0, 100, 50, 50), button3, QRect(0, 50, 50, 50), button4, 171 QRect(0, 0, 50, 50), group) 172 173 state5 = createGeometryState(button1, QRect(100, 100, 50, 50), button2, 174 QRect(150, 100, 50, 50), button3, QRect(100, 150, 50, 50), button4, 175 QRect(150, 150, 50, 50), group) 176 177 state6 = createGeometryState(button1, QRect(50, 50, 50, 50), button2, 178 QRect(200, 50, 50, 50), button3, QRect(50, 200, 50, 50), button4, 179 QRect(200, 200, 50, 50), group) 180 181 state7 = createGeometryState(button1, QRect(0, 0, 50, 50), button2, 182 QRect(250, 0, 50, 50), button3, QRect(0, 250, 50, 50), button4, 183 QRect(250, 250, 50, 50), group) 184 185 group.setInitialState(state1) 186 187 animationGroup = QParallelAnimationGroup() 188 anim = QPropertyAnimation(button4, b'geometry') 189 anim.setDuration(1000) 190 anim.setEasingCurve(QEasingCurve.OutElastic) 191 animationGroup.addAnimation(anim) 192 193 subGroup = QSequentialAnimationGroup(animationGroup) 194 subGroup.addPause(100) 195 anim = QPropertyAnimation(button3, b'geometry') 196 anim.setDuration(1000) 197 anim.setEasingCurve(QEasingCurve.OutElastic) 198 subGroup.addAnimation(anim) 199 200 subGroup = QSequentialAnimationGroup(animationGroup) 201 subGroup.addPause(150) 202 anim = QPropertyAnimation(button2, b'geometry') 203 anim.setDuration(1000) 204 anim.setEasingCurve(QEasingCurve.OutElastic) 205 subGroup.addAnimation(anim) 206 207 subGroup = QSequentialAnimationGroup(animationGroup) 208 subGroup.addPause(200) 209 anim = QPropertyAnimation(button1, b'geometry') 210 anim.setDuration(1000) 211 anim.setEasingCurve(QEasingCurve.OutElastic) 212 subGroup.addAnimation(anim) 213 214 stateSwitcher = StateSwitcher(machine) 215 group.addTransition(timer.timeout, stateSwitcher) 216 stateSwitcher.addState(state1, animationGroup) 217 stateSwitcher.addState(state2, animationGroup) 218 stateSwitcher.addState(state3, animationGroup) 219 stateSwitcher.addState(state4, animationGroup) 220 stateSwitcher.addState(state5, animationGroup) 221 stateSwitcher.addState(state6, animationGroup) 222 stateSwitcher.addState(state7, animationGroup) 223 224 machine.addState(group) 225 machine.setInitialState(group) 226 machine.start() 227 228 window.resize(300, 300) 229 window.show() 230 231 qsrand(QTime(0, 0, 0).secsTo(QTime.currentTime())) 232 233 sys.exit(app.exec_()) 234