Hi,
I've been rewriting the state machine examples into Python with the goal of
uploading them when I'm done.
http://doc.qt.nokia.com/4.7/examples-statemachine.html
However most of them don't work. I've attached them to this email. Only the
first 2 examples work, the last 4 have problems. Like the ping pong one goes
through 3 ping<->pongs and then Segmentation Faults. Yet I don't see any
problem there.
If you take a look at the rogue.py then on line 72, that simple state machine
fails to set the property.
Some examples like these would be very useful examples for showing usage of
signal/slots, properties and state machine in PySide.
from PySide.QtGui import *
from PySide.QtCore import *
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__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')
enterTransition = QEventTransition(button, QEvent.Enter)
enterTransition.setTargetState(s2)
s1.addTransition(enterTransition)
leaveTransition = QEventTransition(button, QEvent.Leave)
leaveTransition.setTargetState(s1)
s2.addTransition(leaveTransition)
s3 = QState()
s3.assignProperty(button, 'text', 'Pressing...')
pressTransition = QEventTransition(button, QEvent.MouseButtonPress)
pressTransition.setTargetState(s3)
s2.addTransition(pressTransition)
releaseTransition = QEventTransition(button, QEvent.MouseButtonRelease)
releaseTransition.setTargetState(s2)
s3.addTransition(releaseTransition)
machine.addState(s1)
machine.addState(s2)
machine.addState(s3)
machine.setInitialState(s1)
machine.start()
self.setCentralWidget(button)
self.show()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
mainWin = MainWindow()
sys.exit(app.exec_())
from PySide.QtGui import *
from PySide.QtCore import *
class Factorial(QObject):
xChanged = Signal(int)
def __init__(self):
super(Factorial, self).__init__()
self.xval = -1
self.facval = 1
def getX(self):
return self.xval
def setX(self, x):
if self.xval == x:
return
self.xval = x
self.xChanged.emit(x)
x = Property(int, getX, setX)
def getFact(self):
return self.facval
def setFact(self, fac):
self.facval = fac
fac = Property(int, getFact, setFact)
class FactorialLoopTransition(QSignalTransition):
def __init__(self, fact):
super(FactorialLoopTransition, self).__init__(fact, SIGNAL('xChanged(int)'))
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(FactorialDoneTransition, self).__init__(fact, SIGNAL('xChanged(int)'))
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__':
import sys
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)
doneTransition = FactorialDoneTransition(factorial)
doneTransition.setTargetState(done)
compute.addTransition(doneTransition)
machine.setInitialState(compute)
machine.finished.connect(app.quit)
machine.start()
sys.exit(app.exec_())
from PySide.QtGui import *
from PySide.QtCore import *
class PingEvent(QEvent):
def __init__(self):
super(PingEvent, self).__init__(QEvent.Type(QEvent.User+2))
class PongEvent(QEvent):
def __init__(self):
super(PongEvent, self).__init__(QEvent.Type(QEvent.User+3))
class Pinger(QState):
def __init__(self, parent):
super(Pinger, self).__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__':
import sys
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_())
from PySide.QtGui import *
from PySide.QtCore import *
class MovementTransition(QEventTransition):
def __init__(self, window):
super(MovementTransition, self).__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:
window.movePlayer(window.Left)
if key == Qt.Key_8:
window.movePlayer(window.Up)
if key == Qt.Key_6:
window.movePlayer(window.Right)
if key == Qt.Key_2:
window.movePlayer(window.Down)
class Custom(QState):
def __init__(self, parent, mw):
self.mw = mw
super(Custom, self).__init__(parent)
def onEntry(self, e):
print(self.mw.status)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.pX = 5
self.pY = 5
self.width = 35
self.height = 20
self.statusStr = ''
database = QFontDatabase()
font = QFont()
if 'Monospace' in database.families():
font = QFont('Monospace', 12)
else:
for family in database.families():
if database.isFixedPitch(family):
font = QFont(family, 12)
self.setFont(font)
self.setupMap()
self.buildMachine()
self.show()
def setupMap(self):
self.map = []
qsrand(QTime(0, 0, 0).secsTo(QTime.currentTime()))
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 qrand() % 40 == 0:
column.append('#')
else:
column.append('.')
self.map.append(column)
def buildMachine(self):
machine = QStateMachine()
inputState = Custom(machine, self)
# this line sets the status
self.status = 'hello!'
# however this line does not
inputState.assignProperty(self, 'status', 'Move the rogue with 2, 4, 6, and 8')
machine.setInitialState(inputState)
machine.start()
"""transition = MovementTransition(self)
inputState.addTransition(transition)
quitState = QState(machine)
quitState.assignProperty(self, 'status', 'Really quit(y/n)?')
yesTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Y)
self.finalState = QFinalState(machine)
yesTransition.setTargetState(self.finalState)
quitState.addTransition(yesTransition)
noTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_N)
noTransition.setTargetState(inputState)
quitState.addTransition(noTransition)
quitTransition = QKeyEventTransition(self, QEvent.KeyPress, Qt.Key_Q)
quitTransition.setTargetState(quitState)
inputState.addTransition(quitTransition)
machine.setInitialState(inputState)
machine.finished.connect(qApp.quit)
machine.start()"""
def sizeHint(self):
metrics = QFontMetrics(self.font())
return QSize(metrics.width('X') * self.width, metrics.height() * (self.height + 1))
def paintEvent(self, event):
metrics = QFontMetrics(self.font())
painter = QPainter(self)
fontHeight = metrics.height()
fontWidth = metrics.width('X')
painter.fillRect(self.rect(), Qt.black)
painter.setPen(Qt.white)
yPos = fontHeight
painter.drawText(QPoint(0, yPos), self.status)
for y in range(self.height):
yPos += fontHeight
xPos = 0
for x in range(self.width):
if y == self.pY and x == self.pX:
xPos += fontWidth
continue
painter.drawText(QPoint(xPos, yPos), self.map[x][y])
xPos += fontWidth
painter.drawText(QPoint(self.pX * fontWidth, (self.pY + 2) * fontHeight), '@')
def movePlayer(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 getStatus(self):
return self.statusStr
def setStatus(self, status):
self.statusStr = status
self.repaint()
status = Property(str, getStatus, setStatus)
Up = 0
Down = 1
Left = 2
Right = 3
Width = 35
Height = 20
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
mainWin = MainWindow()
sys.exit(app.exec_())
from PySide.QtGui import *
from PySide.QtCore import *
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
button = QPushButton(self)
button.setGeometry(QRect(100, 100, 100, 100))
machine = QStateMachine(self)
s1 = QState(machine)
s1.assignProperty(button, 'text', 'Outside')
machine.setInitialState(s1)
machine.start()
self.setCentralWidget(button)
self.show()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
mainWin = MainWindow()
sys.exit(app.exec_())
from PySide.QtGui import *
from PySide.QtCore import *
class LightWidget(QWidget):
def __init__(self, colour):
super(LightWidget, self).__init__()
self.colour = colour
self.onVal = False
def isOn(self):
return self.onVal
def setOn(self, on):
if self.onVal == on:
return
self.onVal = on
self.update()
@Slot()
def turnOff(self):
self.setOn(False)
@Slot()
def turnOn(self):
self.setOn(True)
def paintEvent(self, e):
if not self.onVal:
return
painter = QPainter(self)
painter.setRenderHint(QPainter.Antialiasing)
painter.setBrush(self.colour)
painter.drawEllipse(0, 0, self.width(), self.height())
on = Property(bool, isOn, setOn)
class TrafficLightWidget(QWidget):
def __init__(self):
super(TrafficLightWidget, self).__init__()
vbox = QVBoxLayout(self)
self.redLight = LightWidget(Qt.red)
vbox.addWidget(self.redLight)
self.yellowLight = LightWidget(Qt.yellow)
vbox.addWidget(self.yellowLight)
self.greenLight = LightWidget(Qt.green)
vbox.addWidget(self.greenLight)
pal = QPalette()
pal.setColor(QPalette.Background, Qt.black)
self.setPalette(pal)
self.setAutoFillBackground(True)
def createLightState(light, duration, parent=None):
lightState = QState(parent)
timer = QTimer(lightState)
timer.setInterval(duration)
timer.setSingleShot(True)
timing = QState(lightState)
timing.entered.connect(light.turnOn)
timing.entered.connect(timer.start)
timing.exited.connect(light.turnOff)
done = QFinalState(lightState)
timing.addTransition(timer, SIGNAL('timeout()'), done)
lightState.setInitialState(timing)
return lightState
class TrafficLight(QWidget):
def __init__(self):
super(TrafficLight, self).__init__()
vbox = QVBoxLayout(self)
widget = TrafficLightWidget()
vbox.addWidget(widget)
vbox.setMargin(0)
machine = QStateMachine(self)
redGoingYellow = createLightState(widget.redLight, 3000)
redGoingYellow.setObjectName('redGoingYellow')
yellowGoingGreen = createLightState(widget.redLight, 1000)
yellowGoingGreen.setObjectName('redGoingYellow')
redGoingYellow.addTransition(redGoingYellow, SIGNAL('finished()'), yellowGoingGreen)
greenGoingYellow = createLightState(widget.redLight, 3000)
greenGoingYellow.setObjectName('redGoingYellow')
yellowGoingGreen.addTransition(yellowGoingGreen, SIGNAL('finished()'), greenGoingYellow)
yellowGoingRed = createLightState(widget.redLight, 1000)
yellowGoingRed.setObjectName('redGoingYellow')
greenGoingYellow.addTransition(greenGoingYellow, SIGNAL('finished()'), yellowGoingRed)
yellowGoingRed.addTransition(yellowGoingRed, SIGNAL('finished()'), redGoingYellow)
machine.addState(redGoingYellow)
machine.addState(yellowGoingGreen)
machine.addState(greenGoingYellow)
machine.addState(yellowGoingRed)
machine.setInitialState(redGoingYellow)
machine.start()
if __name__ == '__main__':
import sys
app = QApplication(sys.argv)
widget = TrafficLight()
widget.resize(110, 300)
widget.show()
sys.exit(app.exec_())
from PySide.QtGui import *
from PySide.QtCore import *
if __name__ == '__main__':
import sys
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, SIGNAL('clicked()'), on)
on.addTransition(button, SIGNAL('clicked()'), off)
machine.addState(off)
machine.addState(on)
machine.setInitialState(off)
machine.start()
button.resize(100, 50)
button.show()
sys.exit(app.exec_())
_______________________________________________
PySide mailing list
[email protected]
http://lists.openbossa.org/listinfo/pyside