我可以使用Qt';非图形应用程序中的声明性状态机框架?

我可以使用Qt';非图形应用程序中的声明性状态机框架?,qt,qml,Qt,Qml,我真的很喜欢Qt(DSMF),但我想使用它的方式(可能)有点奇怪。在过去的几年里,我一直在小型(ish)嵌入式设备上的非图形应用程序中大量使用Qt,最近我学习了DSMF,它的语法我非常喜欢 框架名称中的“声明性”限定符似乎表示“在QML文件中声明”,如下所示: StateMachine { id: stateMachine initialState: s1 running: true State { id: s1 Signal

我真的很喜欢Qt(DSMF),但我想使用它的方式(可能)有点奇怪。在过去的几年里,我一直在小型(ish)嵌入式设备上的非图形应用程序中大量使用Qt,最近我学习了DSMF,它的语法我非常喜欢

框架名称中的“声明性”限定符似乎表示“在QML文件中声明”,如下所示:

StateMachine {
    id: stateMachine

    initialState: s1
    running: true

    State {
        id: s1

        SignalTransition {
            targetState: s2
            signal: button.clicked
        }

        // do something when the state enters/exits
        onEntered: console.log("s1 entered")
        onExited: console.log("s1 exited")
    }

    State {

        // create a transition from s2 to s3 when the button is clicked
        SignalTransition {
            targetState: s1
            signal: button.clicked
        }

        onEntered: console.log("s2 entered")
        onExited: console.log("s2 exited")
    }
}

如果我正确地理解了框架,那么我就可以完全定义(一个动态加载的)QML文件中的状态逻辑,并且通过对C++对象的属性(例如,代码> qqMLeNe::StTraceExtPrimeType)(< /代码>)来实现对世界的任何副作用。如果我在这一点上是正确的,我应该能够通过修改QML文件来更改状态机逻辑,而无需重新编译应用程序

我遇到的困难是,我最近才开始学习QML,到目前为止,我发现的大多数(所有?)示例都是针对图形应用程序的。我最初认为QML只用于图形应用程序,但将我引向了一个应用程序,它看起来是一个使用QML的控制台应用程序

我现在正试图区分QB,看看它是否为我如何在控制台应用程序中使用声明性状态机框架提供了任何线索。但我需要一段时间才能弄清楚,我担心在实现我的目标的过程中可能会遇到一些困难


有人能确认在Qt控制台应用程序中是否可以使用DSMF吗?(对于指向或包含具体示例的答案将给予额外的重视…

由于到目前为止还没有任何回复,我将提交我自己对是否可以在非图形应用程序中使用DSMF的问题的答案。它是!我将展示我为满足好奇心而编写的小示例程序。首先,这里是一个C++类,用来模拟一个“域对象”,它知道如何在这个情况下捅开这个世界来达到一些期望的副作用,连接到一个网络:

// File: NetworkManager.h
#ifndef NETWORK_MANAGER_H                                                                                                                                                                 
#define NETWORK_MANAGER_H

#include <QObject>
#include <QTimer>
#include <iostream>

class NetworkManager : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool timedOut MEMBER timedOut_ READ getTimedOut)
public:
    NetworkManager() : timedOut_(false) { }
    ~NetworkManager() { }
    Q_INVOKABLE void connectAsync()
    {
        std::cout << "NetworkManager: In connectAsync(), connecting...\n";

        // Simulate a successful connection within 1 to 5 seconds...
        QTimer::singleShot(
            (1 + qrand() % 5)*1000,
            [this]() {
                std::cout << "NetworkManager: Connected!\n";
                emit this->connected();

                // ... and a random disconnect 5 to 15 seconds later.
                QTimer::singleShot(
                    (5 + qrand() % 11)*1000,
                    [this]() {
                        std::cout << "NetworkManager: Lost connection!\n";
                        emit this->disconnected();
                    }
                );
            }
        );
    }

    bool getTimedOut() const { return timedOut_; }

signals:
    void connected();
    void disconnected();
private:
    bool timedOut_;
};

#endif // NETWORK_MANAGER_H
最后,这里是将两者绑定在一起的
main.cpp
文件,以及构建所有内容的
CMakeLists.txt
文件:

// File: main.cpp
#include <QCoreApplication>                                                                                                                                                               
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <iostream>
#include "NetworkManager.h"

int main(int argc, char *argv[])
{    
    QCoreApplication app(argc, argv);
    NetworkManager network;
    QQmlApplicationEngine engine;

    QQmlContext* context = engine.rootContext();
    context->setContextProperty("network_", &network);
    engine.load(QUrl("./NetworkManagerFsm.qml"));

    return app.exec();
}
下面是我运行它时的样子:

qml: NetworkFsm: sConnecting entered                                                                                                                                                      
NetworkManager: In connectAsync(), connecting...
NetworkManager: Connected!
qml: NetworkFsm: sConnecting exited
qml: NetworkFsm: sConnected entered
NetworkManager: Lost connection!
qml: NetworkFsm: sConnected exited
qml: NetworkFsm: sConnecting entered
NetworkManager: In connectAsync(), connecting...
NetworkManager: Connected!
qml: NetworkFsm: sConnecting exited
qml: NetworkFsm: sConnected entered
^C
所以,是的。。。这是可能的。它是否有用还有待观察。首先,我提出这个问题的动机是想看看我是否能让在Qt中编写状态机更接近我的使用经验——这是一个多年来一直为我服务的工具。我喜欢SMC的
.sm
文件格式的简洁性,以及它没有混杂
标记和其他XML膨胀的事实。DSMF似乎达到了大多数相同的最佳点。时间会证明一切,但是。。。我想至少对于不太复杂的FSM,我更喜欢它而不是SCXML

注意

请理解,上面发布的FSM只是一个拼凑在一起的“玩具”示例,以证明该框架可用于非图形应用程序。请特别注意,
NetworkManager
类的
timedOut
属性仅用于强调导出到QML的
QObject
类的属性可以在保护条件下使用这一事实。(在实际实现中,
timedOut
作为单独的
信号转换
更有意义)

传递给导致转换的信号的参数也可以在保护条件下使用,但我个人认为,当显式访问域对象的属性/方法时,FSM“读取效果更好”。否则,人们会想知道,
timedOut
参数来自何处,必须打开域对象类的头文件才能确定


您希望通过DSMF操作哪些元素?如果你使用C++是因为你不使用?我想要操纵的元素是从QObjor派生的C++对象。我想在QML中定义FSM逻辑,以便以易于阅读的格式将其全部放在一个地方,并且我可以修改逻辑而无需重新编译应用程序。
# File: CMakeLists.txt                                                                                                                                                                    
cmake_minimum_required(VERSION 3.0)
project(qmlfsm)

set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)

find_package(Qt5Core REQUIRED)
find_package(Qt5Qml REQUIRED)

add_executable(qmlfsm main.cpp NetworkManager.h)
target_link_libraries(qmlfsm Qt5::Core Qt5::Qml)
qml: NetworkFsm: sConnecting entered                                                                                                                                                      
NetworkManager: In connectAsync(), connecting...
NetworkManager: Connected!
qml: NetworkFsm: sConnecting exited
qml: NetworkFsm: sConnected entered
NetworkManager: Lost connection!
qml: NetworkFsm: sConnected exited
qml: NetworkFsm: sConnecting entered
NetworkManager: In connectAsync(), connecting...
NetworkManager: Connected!
qml: NetworkFsm: sConnecting exited
qml: NetworkFsm: sConnected entered
^C