我正在尝试使用后端的 Python、前端的 QML 和用于创建状态机的 scxml 编写桌面应用程序。我正在使用 PySide2。我的目的是通过状态机来描述应用程序的逻辑。基于状态,QML 中的 UI 应该做出相应的反应。此外,后端应根据进入状态等执行方法。
我的项目包含 3 个文件:main.py
带有后端逻辑、ui.qml
带有 UI、stateMachine.scxml
带有状态机。
内容main.py
:
from PySide2.QtScxml import QScxmlStateMachine
from PySide2.QtWidgets import QApplication
from PySide2.QtCore import QUrl, QObject, Slot
from PySide2.QtQml import QQmlApplicationEngine
class BackEnd(QObject):
def __init__(self):
super().__init__()
@Slot()
def ev_slot(self):
'''method called on event t1'''
print('event t1')
@Slot(bool)
def st_slot(self, active):
'''method called on entering and exiting state s2'''
if active:
print('s2 entered')
else:
print('s2 exited')
app = QApplication([])
qml_url = QUrl("ui.qml")
engine = QQmlApplicationEngine()
# loading state machine
my_state_machine = QScxmlStateMachine.fromFile('stateMachine.scxml')
backend = BackEnd()
# registering state machine in QML context
engine.rootContext().setContextProperty("stateMachine", my_state_machine)
# connecting event of state machine to method of backend
conn1 = my_state_machine.connectToEvent("t1", backend, "aev_slot()")
# connecting state of state machine to method of backend
conn2 = my_state_machine.connectToState("s2", backend, "ast_slot(bool)")
my_state_machine.start()
engine.load(qml_url)
app.exec_()
UI 非常简单:它仅包含 3 个向状态机(ui.qml
文件)提交事件的按钮:
import QtQuick 2.0
import QtQuick.Controls 2.2
ApplicationWindow {
width: column.width
height: column.height
visible: true
Column {
id: column
spacing: 10
Button {
id: button0
text: qsTr("t1")
onClicked: stateMachine.submitEvent('t1')
}
Button {
id: button1
text: qsTr("t2")
onClicked: stateMachine.submitEvent('t2')
}
Button {
id: button2
text: qsTr("t3")
onClicked: stateMachine.submitEvent('t3')
}
}
}
状态机stateMachine.scxml
由 3 个状态组成:、s1
和转换、s2
、:s3
t1
t2
t3
<?xml version="1.0" encoding="UTF-8"?>
<scxml xmlns="http://www.w3.org/2005/07/scxml" version="1.0" binding="early" xmlns:qt="http://www.qt.io/2015/02/scxml-ext" name="stateMachine" initial="s1">
<state id="s1">
<transition type="external" event="t1" target="s2"/>
<onentry>
<log label="entered" expr="s1"/>
</onentry>
</state>
<state id="s2">
<transition type="external" event="t2" target="s3"/>
<onentry>
<log label="entered" expr="s2"/>
</onentry>
</state>
<state id="s3">
<transition type="external" event="t3" target="s1">
</transition>
<onentry>
<log label="entered" expr="s3"/>
</onentry>
</state>
</scxml>
这里的问题是一切正常。行my_state_machine.connectToEvent("t1", backend, "aev_slot()")
有一个错误:方法名称是ev_slot()
,不是aev_slot()
。但是,如果我将其更改为正确的名称,则会收到以下错误:
QObject::connect: No such slot BackEnd::v_slot()
不知何故,方法名称中的第一个字母被忽略了。难道我做错了什么?我对 Qt 和 PySide2 很陌生。总的来说这是一个好方法吗?我正在使用 PySide2 5.11.1a1.dev1530708810518