diff options
author | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-09-15 13:21:53 +0200 |
---|---|---|
committer | Friedemann Kleint <Friedemann.Kleint@qt.io> | 2022-09-16 10:30:36 +0200 |
commit | cf32b66adbfb489cd6e5d5c0bf3f741b59ba204c (patch) | |
tree | 44be69c9487f5d4db1092d061a555bd6001c1ab4 /examples/statemachine | |
parent | b20d6f6906f91f9df608d7800f4e27f7a7160abe (diff) |
Move examples around
Change the directory structure to closer match that of Qt.
Task-number: PYSIDE-841
Change-Id: I87aca346b6654aafe94dd1fb83c184c182ceb2e6
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io>
Diffstat (limited to 'examples/statemachine')
-rw-r--r-- | examples/statemachine/eventtrans/eventtrans.py | 57 | ||||
-rw-r--r-- | examples/statemachine/eventtrans/eventtrans.pyproject | 3 | ||||
-rw-r--r-- | examples/statemachine/factstates/factstates.py | 89 | ||||
-rw-r--r-- | examples/statemachine/factstates/factstates.pyproject | 3 | ||||
-rw-r--r-- | examples/statemachine/ping_pong/ping_pong.py | 70 | ||||
-rw-r--r-- | examples/statemachine/ping_pong/ping_pong.pyproject | 3 | ||||
-rw-r--r-- | examples/statemachine/rogue/rogue.py | 179 | ||||
-rw-r--r-- | examples/statemachine/rogue/rogue.pyproject | 3 | ||||
-rw-r--r-- | examples/statemachine/trafficlight/doc/trafficlight.png | bin | 0 -> 79 bytes | |||
-rw-r--r-- | examples/statemachine/trafficlight/doc/trafficlight.rst | 10 | ||||
-rw-r--r-- | examples/statemachine/trafficlight/trafficlight.py | 117 | ||||
-rw-r--r-- | examples/statemachine/trafficlight/trafficlight.pyproject | 3 | ||||
-rw-r--r-- | examples/statemachine/twowaybutton/twowaybutton.py | 33 | ||||
-rw-r--r-- | examples/statemachine/twowaybutton/twowaybutton.pyproject | 3 |
14 files changed, 573 insertions, 0 deletions
diff --git a/examples/statemachine/eventtrans/eventtrans.py b/examples/statemachine/eventtrans/eventtrans.py new file mode 100644 index 000000000..b1c74a21f --- /dev/null +++ b/examples/statemachine/eventtrans/eventtrans.py @@ -0,0 +1,57 @@ +# Copyright (C) 2010 velociraptor Genjix <aphidia@hotmail.com> +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import sys + +from PySide6.QtCore import QEvent, QRect, Qt +from PySide6.QtWidgets import QApplication, QMainWindow, QPushButton +from PySide6.QtStateMachine import QEventTransition, QState, QStateMachine + + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + button = QPushButton(self) + button.setGeometry(QRect(100, 100, 100, 100)) + + machine = QStateMachine(self) + s1 = QState() + s1.assignProperty(button, 'text', 'Outside') + s2 = QState() + s2.assignProperty(button, 'text', 'Inside') + + enter_transition = QEventTransition(button, QEvent.Enter) + enter_transition.setTargetState(s2) + s1.addTransition(enter_transition) + + leave_transition = QEventTransition(button, QEvent.Leave) + leave_transition.setTargetState(s1) + s2.addTransition(leave_transition) + + s3 = QState() + s3.assignProperty(button, 'text', 'Pressing...') + + press_transition = QEventTransition(button, QEvent.MouseButtonPress) + press_transition.setTargetState(s3) + s2.addTransition(press_transition) + + release_transition = QEventTransition(button, QEvent.MouseButtonRelease) + release_transition.setTargetState(s2) + s3.addTransition(release_transition) + + machine.addState(s1) + machine.addState(s2) + machine.addState(s3) + + machine.setInitialState(s1) + machine.start() + + self.setCentralWidget(button) + self.show() + + +if __name__ == '__main__': + app = QApplication(sys.argv) + main_win = MainWindow() + sys.exit(app.exec()) diff --git a/examples/statemachine/eventtrans/eventtrans.pyproject b/examples/statemachine/eventtrans/eventtrans.pyproject new file mode 100644 index 000000000..b2f660a8f --- /dev/null +++ b/examples/statemachine/eventtrans/eventtrans.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["eventtrans.py"] +} diff --git a/examples/statemachine/factstates/factstates.py b/examples/statemachine/factstates/factstates.py new file mode 100644 index 000000000..aacf8f19b --- /dev/null +++ b/examples/statemachine/factstates/factstates.py @@ -0,0 +1,89 @@ +# Copyright (C) 2010 velociraptor Genjix <aphidia@hotmail.com> +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import sys + +from PySide6.QtCore import QCoreApplication, QObject, Qt, Property, Signal +from PySide6.QtStateMachine import (QFinalState, QSignalTransition, QState, + QStateMachine) + + +class Factorial(QObject): + x_changed = Signal(int) + + def __init__(self): + super().__init__() + self.xval = -1 + self.facval = 1 + + def get_x(self): + return self.xval + + def set_x(self, x): + if self.xval == x: + return + self.xval = x + self.x_changed.emit(x) + x = Property(int, get_x, set_x) + + def get_fact(self): + return self.facval + + def set_fact(self, fac): + self.facval = fac + + fac = Property(int, get_fact, set_fact) + + +class FactorialLoopTransition(QSignalTransition): + def __init__(self, fact): + super().__init__(fact.x_changed) + self.fact = fact + + def eventTest(self, e): + if not super(FactorialLoopTransition, self).eventTest(e): + return False + return e.arguments()[0] > 1 + + def onTransition(self, e): + x = e.arguments()[0] + fac = self.fact.fac + self.fact.fac = x * fac + self.fact.x = x - 1 + + +class FactorialDoneTransition(QSignalTransition): + def __init__(self, fact): + super().__init__(fact.x_changed) + self.fact = fact + + def eventTest(self, e): + if not super(FactorialDoneTransition, self).eventTest(e): + return False + return e.arguments()[0] <= 1 + + def onTransition(self, e): + print(self.fact.fac) + + +if __name__ == '__main__': + app = QCoreApplication(sys.argv) + factorial = Factorial() + machine = QStateMachine() + + compute = QState(machine) + compute.assignProperty(factorial, 'fac', 1) + compute.assignProperty(factorial, 'x', 6) + compute.addTransition(FactorialLoopTransition(factorial)) + + done = QFinalState(machine) + done_transition = FactorialDoneTransition(factorial) + done_transition.setTargetState(done) + compute.addTransition(done_transition) + + machine.setInitialState(compute) + machine.finished.connect(app.quit) + machine.start() + + sys.exit(app.exec()) diff --git a/examples/statemachine/factstates/factstates.pyproject b/examples/statemachine/factstates/factstates.pyproject new file mode 100644 index 000000000..751a5005b --- /dev/null +++ b/examples/statemachine/factstates/factstates.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["factstates.py"] +} diff --git a/examples/statemachine/ping_pong/ping_pong.py b/examples/statemachine/ping_pong/ping_pong.py new file mode 100644 index 000000000..d5c18eb28 --- /dev/null +++ b/examples/statemachine/ping_pong/ping_pong.py @@ -0,0 +1,70 @@ +# Copyright (C) 2010 velociraptor Genjix <aphidia@hotmail.com> +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import sys + +from PySide6.QtCore import QCoreApplication, QEvent +from PySide6.QtStateMachine import QAbstractTransition, QState, QStateMachine + + +class PingEvent(QEvent): + def __init__(self): + super().__init__(QEvent.Type(QEvent.User + 2)) + + +class PongEvent(QEvent): + def __init__(self): + super().__init__(QEvent.Type(QEvent.User + 3)) + + +class Pinger(QState): + def __init__(self, parent): + super().__init__(parent) + + def onEntry(self, e): + self.p = PingEvent() + self.machine().postEvent(self.p) + print('ping?') + + +class PongTransition(QAbstractTransition): + def eventTest(self, e): + return e.type() == QEvent.User + 3 + + def onTransition(self, e): + self.p = PingEvent() + machine.postDelayedEvent(self.p, 500) + print('ping?') + + +class PingTransition(QAbstractTransition): + def eventTest(self, e): + return e.type() == QEvent.User + 2 + + def onTransition(self, e): + self.p = PongEvent() + machine.postDelayedEvent(self.p, 500) + print('pong!') + + +if __name__ == '__main__': + app = QCoreApplication(sys.argv) + + machine = QStateMachine() + group = QState(QState.ParallelStates) + group.setObjectName('group') + + pinger = Pinger(group) + pinger.setObjectName('pinger') + pinger.addTransition(PongTransition()) + + ponger = QState(group) + ponger.setObjectName('ponger') + ponger.addTransition(PingTransition()) + + machine.addState(group) + machine.setInitialState(group) + machine.start() + + sys.exit(app.exec()) diff --git a/examples/statemachine/ping_pong/ping_pong.pyproject b/examples/statemachine/ping_pong/ping_pong.pyproject new file mode 100644 index 000000000..7fb430352 --- /dev/null +++ b/examples/statemachine/ping_pong/ping_pong.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["ping_pong.py"] +} diff --git a/examples/statemachine/rogue/rogue.py b/examples/statemachine/rogue/rogue.py new file mode 100644 index 000000000..a43d4d1bc --- /dev/null +++ b/examples/statemachine/rogue/rogue.py @@ -0,0 +1,179 @@ +# Copyright (C) 2010 velociraptor Genjix <aphidia@hotmail.com> +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import sys + +from PySide6.QtCore import (QEvent, QPoint, QRandomGenerator, QSize, Qt, + Property) +from PySide6.QtGui import QFont, QFontMetrics, QFontDatabase, QPainter +from PySide6.QtWidgets import QApplication, QMainWindow +from PySide6.QtStateMachine import (QEventTransition, QFinalState, + QKeyEventTransition, QState, QStateMachine) + + +class MovementTransition(QEventTransition): + def __init__(self, window): + super().__init__(window, QEvent.KeyPress) + self.window = window + + def eventTest(self, event): + if (event.type() == QEvent.StateMachineWrapped and + event.event().type() == QEvent.KeyPress): + key = event.event().key() + return (key == Qt.Key_2 or key == Qt.Key_8 or + key == Qt.Key_6 or key == Qt.Key_4) + return False + + def onTransition(self, event): + key = event.event().key() + if key == Qt.Key_4: + self.window.move_player(self.window.left) + if key == Qt.Key_8: + self.window.move_player(self.window.Up) + if key == Qt.Key_6: + self.window.move_player(self.window.right) + if key == Qt.Key_2: + self.window.move_player(self.window.down) + + +class Custom(QState): + def __init__(self, parent, mw): + super().__init__(parent) + self.mw = mw + + def onEntry(self, e): + print(self.mw.status) + + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + self.pX = 5 + self.pY = 5 + self.width = 35 + self.height = 20 + self._status_str = '' + + font = QFont() + if 'Monospace' in QFontDatabase.families(): + font = QFont('Monospace', 12) + else: + for family in QFontDatabase.families(): + if QFontDatabase.isFixedPitch(family): + font = QFont(family, 12) + self.setFont(font) + + self.setup_map() + self.build_machine() + self.show() + + def setup_map(self): + self.map = [] + generator = QRandomGenerator().global_() + for x in range(self.width): + column = [] + for y in range(self.height): + if (x == 0 or x == self.width - 1 or y == 0 or + y == self.height - 1 or generator.bounded(0, 40) == 0): + column.append('#') + else: + column.append('.') + self.map.append(column) + + def build_machine(self): + machine = QStateMachine(self) + + input_state = Custom(machine, self) + # this line sets the status + self.status = 'hello!' + # however this line does not + input_state.assignProperty(self, 'status', 'Move the rogue with 2, 4, 6, and 8') + + machine.setInitialState(input_state) + machine.start() + + transition = MovementTransition(self) + input_state.addTransition(transition) + + quit_state = QState(machine) + quit_state.assignProperty(self, 'status', 'Really quit(y/n)?') + + yes_transition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Y) + self._final_state = QFinalState(machine) + yes_transition.setTargetState(self._final_state) + quit_state.addTransition(yes_transition) + + no_transition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_N) + no_transition.setTargetState(input_state) + quit_state.addTransition(no_transition) + + quit_transition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Q) + quit_transition.setTargetState(quit_state) + input_state.addTransition(quit_transition) + + machine.setInitialState(input_state) + machine.finished.connect(qApp.quit) + machine.start() + + def sizeHint(self): + metrics = QFontMetrics(self.font()) + return QSize(metrics.horizontalAdvance('X') * self.width, + metrics.height() * (self.height + 1)) + + def paintEvent(self, event): + metrics = QFontMetrics(self.font()) + with QPainter(self) as painter: + font_height = metrics.height() + font_width = metrics.horizontalAdvance('X') + + painter.fillRect(self.rect(), Qt.black) + painter.setPen(Qt.white) + + y_pos = font_height + painter.drawText(QPoint(0, y_pos), self.status) + for y in range(self.height): + y_pos += font_height + x_pos = 0 + for x in range(self.width): + if y == self.pY and x == self.pX: + x_pos += font_width + continue + painter.drawText(QPoint(x_pos, y_pos), self.map[x][y]) + x_pos += font_width + painter.drawText(QPoint(self.pX * font_width, (self.pY + 2) * font_height), '@') + + def move_player(self, direction): + if direction == self.left: + if self.map[self.pX - 1][self.pY] != '#': + self.pX -= 1 + elif direction == self.right: + if self.map[self.pX + 1][self.pY] != '#': + self.pX += 1 + elif direction == self.Up: + if self.map[self.pX][self.pY - 1] != '#': + self.pY -= 1 + elif direction == self.down: + if self.map[self.pX][self.pY + 1] != '#': + self.pY += 1 + self.repaint() + + def get_status(self): + return self._status_str + + def set_status(self, status): + self._status_str = status + self.repaint() + status = Property(str, get_status, set_status) + Up = 0 + down = 1 + left = 2 + right = 3 + width = 35 + height = 20 + + +if __name__ == '__main__': + app = QApplication(sys.argv) + main_win = MainWindow() + sys.exit(app.exec()) diff --git a/examples/statemachine/rogue/rogue.pyproject b/examples/statemachine/rogue/rogue.pyproject new file mode 100644 index 000000000..b8baf9802 --- /dev/null +++ b/examples/statemachine/rogue/rogue.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["rogue.py"] +} diff --git a/examples/statemachine/trafficlight/doc/trafficlight.png b/examples/statemachine/trafficlight/doc/trafficlight.png Binary files differnew file mode 100644 index 000000000..ec88a8e8b --- /dev/null +++ b/examples/statemachine/trafficlight/doc/trafficlight.png diff --git a/examples/statemachine/trafficlight/doc/trafficlight.rst b/examples/statemachine/trafficlight/doc/trafficlight.rst new file mode 100644 index 000000000..57d369465 --- /dev/null +++ b/examples/statemachine/trafficlight/doc/trafficlight.rst @@ -0,0 +1,10 @@ +Traffic Light Example +===================== + +The Traffic Light example shows how to use The State Machine Framework to +implement the control flow of a traffic light. + + +.. image:: trafficlight.png + :width: 400 + :alt: Traffic Light Screenshot diff --git a/examples/statemachine/trafficlight/trafficlight.py b/examples/statemachine/trafficlight/trafficlight.py new file mode 100644 index 000000000..1e58384f9 --- /dev/null +++ b/examples/statemachine/trafficlight/trafficlight.py @@ -0,0 +1,117 @@ +# Copyright (C) 2010 velociraptor Genjix <aphidia@hotmail.com> +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import sys + +from PySide6.QtCore import QTimer, Qt, Property, Slot +from PySide6.QtGui import QPainter, QPalette +from PySide6.QtWidgets import QApplication, QVBoxLayout, QWidget +from PySide6.QtStateMachine import QFinalState, QState, QStateMachine + + +class LightWidget(QWidget): + def __init__(self, color): + super().__init__() + self.color = color + self._on_val = False + + def is_on(self): + return self._on_val + + def set_on(self, on): + if self._on_val == on: + return + self._on_val = on + self.update() + + @Slot() + def turn_off(self): + self.set_on(False) + + @Slot() + def turn_on(self): + self.set_on(True) + + def paintEvent(self, e): + if not self._on_val: + return + with QPainter(self) as painter: + painter.setRenderHint(QPainter.Antialiasing) + painter.setBrush(self.color) + painter.drawEllipse(0, 0, self.width(), self.height()) + + on = Property(bool, is_on, set_on) + + +class TrafficLightWidget(QWidget): + def __init__(self): + super().__init__() + vbox = QVBoxLayout(self) + self._red_light = LightWidget(Qt.red) + vbox.addWidget(self._red_light) + self._yellow_light = LightWidget(Qt.yellow) + vbox.addWidget(self._yellow_light) + self._green_light = LightWidget(Qt.green) + vbox.addWidget(self._green_light) + pal = QPalette() + pal.setColor(QPalette.Window, Qt.black) + self.setPalette(pal) + self.setAutoFillBackground(True) + + +def create_light_state(light, duration, parent=None): + light_state = QState(parent) + timer = QTimer(light_state) + timer.setInterval(duration) + timer.setSingleShot(True) + timing = QState(light_state) + timing.entered.connect(light.turn_on) + timing.entered.connect(timer.start) + timing.exited.connect(light.turn_off) + done = QFinalState(light_state) + timing.addTransition(timer.timeout, done) + light_state.setInitialState(timing) + return light_state + + +class TrafficLight(QWidget): + def __init__(self): + super().__init__() + vbox = QVBoxLayout(self) + widget = TrafficLightWidget() + vbox.addWidget(widget) + vbox.setContentsMargins(0, 0, 0, 0) + + machine = QStateMachine(self) + red_going_yellow = create_light_state(widget._red_light, 1000) + red_going_yellow.setObjectName('redGoingYellow') + yellow_going_green = create_light_state(widget._red_light, 1000) + yellow_going_green.setObjectName('yellowGoingGreen') + red_going_yellow.addTransition(red_going_yellow.finished, + yellow_going_green) + green_going_yellow = create_light_state(widget._yellow_light, 3000) + green_going_yellow.setObjectName('greenGoingYellow') + yellow_going_green.addTransition(yellow_going_green.finished, + green_going_yellow) + yellow_going_red = create_light_state(widget._green_light, 1000) + yellow_going_red.setObjectName('yellowGoingRed') + green_going_yellow.addTransition(green_going_yellow.finished, + yellow_going_red) + yellow_going_red.addTransition(yellow_going_red.finished, + red_going_yellow) + + machine.addState(red_going_yellow) + machine.addState(yellow_going_green) + machine.addState(green_going_yellow) + machine.addState(yellow_going_red) + machine.setInitialState(red_going_yellow) + machine.start() + + +if __name__ == '__main__': + app = QApplication(sys.argv) + widget = TrafficLight() + widget.resize(110, 300) + widget.show() + sys.exit(app.exec()) diff --git a/examples/statemachine/trafficlight/trafficlight.pyproject b/examples/statemachine/trafficlight/trafficlight.pyproject new file mode 100644 index 000000000..912472693 --- /dev/null +++ b/examples/statemachine/trafficlight/trafficlight.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["trafficlight.py"] +} diff --git a/examples/statemachine/twowaybutton/twowaybutton.py b/examples/statemachine/twowaybutton/twowaybutton.py new file mode 100644 index 000000000..35a582f93 --- /dev/null +++ b/examples/statemachine/twowaybutton/twowaybutton.py @@ -0,0 +1,33 @@ +# Copyright (C) 2010 velociraptor Genjix <aphidia@hotmail.com> +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause + +import sys + +from PySide6.QtWidgets import QApplication, QPushButton +from PySide6.QtStateMachine import QState, QStateMachine + + +if __name__ == '__main__': + app = QApplication(sys.argv) + button = QPushButton() + machine = QStateMachine() + + off = QState() + off.assignProperty(button, 'text', 'Off') + off.setObjectName('off') + + on = QState() + on.setObjectName('on') + on.assignProperty(button, 'text', 'On') + + off.addTransition(button.clicked, on) + on.addTransition(button.clicked, off) + + machine.addState(off) + machine.addState(on) + machine.setInitialState(off) + machine.start() + button.resize(100, 50) + button.show() + sys.exit(app.exec()) diff --git a/examples/statemachine/twowaybutton/twowaybutton.pyproject b/examples/statemachine/twowaybutton/twowaybutton.pyproject new file mode 100644 index 000000000..223a51e32 --- /dev/null +++ b/examples/statemachine/twowaybutton/twowaybutton.pyproject @@ -0,0 +1,3 @@ +{ + "files": ["twowaybutton.py"] +} |