1.首先创建配置文件(JSON 格式):
// states_config.json
{
"states": [
{
"name": "InitState",
"qmlPath": "qrc:/qml/InitPage.qml",
"transitions": [
{
"event": "init_completed",
"target": "MainState"
}
]
},
{
"name": "MainState",
"qmlPath": "qrc:/qml/MainPage.qml",
"transitions": [
{
"event": "to_settings",
"target": "SettingsState"
}
]
},
{
"name": "SettingsState",
"qmlPath": "qrc:/qml/SettingsPage.qml",
"transitions": [
{
"event": "back",
"target": "MainState"
}
]
}
]
}
2.创建状态机管理类:
// statemanager.h
#ifndef STATEMANAGER_H
#define STATEMANAGER_H
#include <QObject>
#include <QStateMachine>
#include <QState>
#include <QMap>
#include <QJsonObject>
class StateManager : public QObject
{
Q_OBJECT
Q_PROPERTY(QString currentQmlPath READ currentQmlPath NOTIFY currentQmlPathChanged)
public:
explicit StateManager(QObject *parent = nullptr);
void loadConfig(const QString &configPath);
QString currentQmlPath() const;
Q_INVOKABLE void triggerEvent(const QString &event);
signals:
void currentQmlPathChanged(const QString &path);
void stateChanged(const QString &stateName);
private:
void setupState(const QJsonObject &stateConfig);
QStateMachine m_machine;
QMap<QString, QState*> m_states;
QMap<QString, QString> m_stateQmlPaths;
QString m_currentQmlPath;
};
#endif // STATEMANAGER_H
// statemanager.cpp
#include "statemanager.h"
#include <QFile>
#include <QJsonDocument>
#include <QJsonArray>
#include <QJsonObject>
StateManager::StateManager(QObject *parent)
: QObject(parent)
{
}
void StateManager::loadConfig(const QString &configPath)
{
QFile file(configPath);
if (!file.open(QIODevice::ReadOnly)) {
qWarning() << "Failed to open config file:" << configPath;
return;
}
QJsonDocument doc = QJsonDocument::fromJson(file.readAll());
QJsonArray states = doc.object()["states"].toArray();
// 创建所有状态
for (const QJsonValue &stateValue : states) {
QJsonObject stateObj = stateValue.toObject();
setupState(stateObj);
}
// 设置转换
for (const QJsonValue &stateValue : states) {
QJsonObject stateObj = stateValue.toObject();
QString stateName = stateObj["name"].toString();
QState *state = m_states[stateName];
QJsonArray transitions = stateObj["transitions"].toArray();
for (const QJsonValue &transValue : transitions) {
QJsonObject transObj = transValue.toObject();
QString event = transObj["event"].toString();
QString target = transObj["target"].toString();
if (m_states.contains(target)) {
state->addTransition(this,
SIGNAL(eventTriggered(QString)),
m_states[target]);
}
}
}
// 启动状态机
m_machine.start();
}
void StateManager::setupState(const QJsonObject &stateConfig)
{
QString stateName = stateConfig["name"].toString();
QString qmlPath = stateConfig["qmlPath"].toString();
QState *state = new QState(&m_machine);
m_states[stateName] = state;
m_stateQmlPaths[stateName] = qmlPath;
connect(state, &QState::entered, this, [this, qmlPath, stateName]() {
m_currentQmlPath = qmlPath;
emit currentQmlPathChanged(qmlPath);
emit stateChanged(stateName);
});
}
void StateManager::triggerEvent(const QString &event)
{
emit eventTriggered(event);
}
QString StateManager::currentQmlPath() const
{
return m_currentQmlPath;
}
3. 主窗口 QML 文件:
// main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
visible: true
width: 800
height: 600
title: qsTr("State Machine Demo")
Loader {
id: pageLoader
anchors.fill: parent
source: stateManager.currentQmlPath
}
}
4.示例页面 QML 文件:
// InitPage.qml
import QtQuick 2.15
Rectangle {
color: "lightblue"
Text {
anchors.centerIn: parent
text: "Init Page"
}
MouseArea {
anchors.fill: parent
onClicked: {
stateManager.triggerEvent("init_completed")
}
}
}
// MainPage.qml
import QtQuick 2.15
Rectangle {
color: "lightgreen"
Text {
anchors.centerIn: parent
text: "Main Page"
}
MouseArea {
anchors.fill: parent
onClicked: {
stateManager.triggerEvent("to_settings")
}
}
}
5.在 main.cpp 中设置:
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "statemanager.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
StateManager stateManager;
stateManager.loadConfig(":/config/states_config.json");
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("stateManager", &stateManager);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
6.项目文件 (qml.qrc):
<RCC>
<qresource prefix="/">
<file>main.qml</file>
<file>qml/InitPage.qml</file>
<file>qml/MainPage.qml</file>
<file>qml/SettingsPage.qml</file>
<file>config/states_config.json</file>
</qresource>
</RCC>
使用这个实现的优点:
配置驱动:
- 状态和转换通过配置文件定义
- 易于修改和维护
- 可以动态加载不同配置
解耦:
- QML 页面与状态逻辑分离
- 状态转换逻辑集中管理
- 页面可以独立开发和测试
扩展性:
- 易于添加新状态和页面
- 可以添加状态转换条件
- 可以添加状态进入/退出动作
调试友好:
- 状态变化可以记录日志
- 可以监控状态转换
- 配置文件易于检查
可以根据需要扩展功能:
- 添加状态转换动画
- 添加状态历史
- 添加条件转换
- 添加状态数据
- 添加错误处理
- 添加状态持久化
使用时注意:
- 确保配置文件格式正确
- 处理文件加载错误
- 验证状态转换的有效性
- 考虑添加状态转换的权限控制
- 考虑添加状态转换的日志记录