3

我正在尝试构建一个系统,该系统由主状态机编排,并针对正在执行的任务具有不同的子状态机。作为一个长期使用 Qt 的用户,我查看了 Qt 5.8 中新的 SCXML 实现。但是我无法弄清楚如何使用 5.8 提供的 API 来正确实现子状态机。

我的想法是使用一个主状态机,然后在主状态机的状态下调用特定的子状态机。在调用子状态机工作时,我无法弄清楚在顶级状态机对象发出后如何访问它们,invokedServicesChanged(..)我可以访问指向 QScxmlInvokableService但不能访问相关状态机的指针。

此外,顶级状态机对象仅从顶部公开状态和事件,而不是从调用的状态机公开。例如 topLevelStateMachine->activeStateNames()只列出顶级状态。

查看 Qt 的源代码,我看到它QScxmlInvokableService实际上是一个基类,QScxmlScxmlService其中包含一个指向相关状态机的指针。不幸的是,正如名称所示,它QScxmlScxmlService被定义qscxmlinvokableservice_p.h为私有。_p那么我应该如何使用公共 SCXML API?我错过了什么吗?IIRC SCXML 支持是 5.7 中的技术预览,但现在作为正常分布的一部分包含在 5.8 中。

4

1 回答 1

0

我花了大约一周的时间研究这些示例,然后编写我自己的状态机和响应它的代码。由于文档不够清晰,因此花了一段时间。

我发现activeStateNames确实检索了状态机中包含的所有状态,包括子状态。

我花了几次阅读交通灯示例来弄清楚这一点。关键是子状态机包含在特定状态中。(状态机的图形视图在这里有所帮助。)

在该示例中,总体顶级机器中只有两个状态:workingbroken。转换由事件smash和控制repair

在这两个状态中的每一个中都有较小的状态机。Broken 包含两个状态的状态机:blinkingunblinking。该状态机在进入blinking时的状态下启动broken

当 处于 的子状态blinking时,如果使用(默认)调用或使用调用时broken,activeStateNames 将返回。blinkingfalseblinkingbrokentrue

那么你如何使用它呢?

如果我有一些我想根据特定状态设置/取消设置的东西,我可以connectToState在机器中。当状态在活动和非活动之间变化时,我连接的插槽将被调用,它会收到一个布尔值,说明状态是否处于活动状态。在交通灯示例中,状态red连接到redLight. 由于redLight在该状态下应该打开red而不是其他状态,因此它连接到一个插槽,需要一个布尔值:打开灯,关闭true灯。false

好的,但是如果我想在进入状态时捕捉事件怎么办?

我只需选择状态,然后添加一个 onEntry -> send 并指定事件名称。当我进入该状态时,这将导致发送一个事件。此事件可以使用connectToEvent. [Qt 5.7 版本只有一个通用eventOccurred信号,您可以将其发送到插槽,然后使用 event.name() 查询哪个事件。]

于 2017-02-13T20:57:59.420 回答