Qt状态机学习3

Wesley13
• 阅读 671

                      在使用状态机表述的系统中中存在一个属性,这个属性取值都是是互相排斥的,比如电源有打开和关闭,灯有亮和灭,但是不一定只有两个取值。我们的理想状态机不可能只有一个单一的属性。

                      下面我们举一个例子,在一个状态机中存在下面这几种属性,每个属性都有几个取值。

                       Qt状态机学习3

                       所以就会有四种状态,2*2 = 4;如果每个状态都是可以互相转换的饿,那么就是4*2 = 8中过渡。

                       如果又添加了一种属性

                         Qt状态机学习3

                       那么就是2*2*3=12中状态,12*2 = 24中过渡,是指数级的增长,而且在添加和移除属性是,会影响状态。

                       在此Qt的QState类中有一个枚举类型

                       Qt状态机学习3

                        第二个平行的状态集就是为了解决这个问题。

#include <QApplication>
#include <QState>
#include <QStateMachine>
#include <QPushButton>
#include <QVariant>
#include <QFinalState>
#include <QLayout>
#include <QHistoryState>
#include <QLabel>
#include <QMessageBox>
#include <QtDebug>
#include <QAbstractTransition>




//Qt的状态机是层次的,是事件驱动的,使用到了事件循环,那么就是异步的
int main(int argc, char* argv[])
{
    QApplication app(argc,argv);

    QStateMachine sMachine;//一个状态机对象
    QState s;//和fState在同一个层次

    QState s0;//开始状态,空白状态
    QState s1;//3个状态对象
    s1.setChildMode(QState::ParallelStates);
    s1.setParent(&s);
    QState s2;
    s2.setParent(&s);
    QState s3;
    s3.setParent(&s);
    s.setInitialState(&s1);//一组状态中要指定一组状态中的初始状态


    QState s11;
    s11.setChildMode(QState::ExclusiveStates);
    s11.setParent(&s1);
    QState s111;//a1
    s111.setParent(&s11);
    QState s112;//a2
    s112.setParent(&s11);
    s11.setInitialState(&s111);
    QState s12;
    s12.setChildMode(QState::ExclusiveStates);
    s12.setParent(&s1);
    QState s121;//b1
    s121.setParent(&s12);
    QState s122;//b2
    s122.setParent(&s12);
    s12.setInitialState(&s121);




    QHistoryState sh;//记录s组状态被打断的状态
    sh.setParent(&s);
    QFinalState fState;

    QState is;//中断状态

    QWidget w;
    QHBoxLayout layout;
    QPushButton button(QObject::tr("状态改变"));
    QPushButton qButton;
    QPushButton startButton("start");
    QPushButton stopButton("stop");
    qButton.setText(QObject::tr("退出"));
    QPushButton iButton;
    iButton.setText(QObject::tr("打断"));

    QPushButton button1("a1,b1");
    QPushButton button2("a1,b2");
    QPushButton button3("a2,b1");
    QPushButton button4("a2,b2");

    QLabel showLabel;
    QLabel showLabel2;
    QLabel showLabel3;
    layout.addWidget(&button);
    layout.addWidget(&qButton);
    layout.addWidget(&iButton);
    layout.addWidget(&showLabel);
    layout.addWidget(&showLabel2);
    layout.addWidget(&showLabel3);
    layout.addWidget(&startButton);
    layout.addWidget(&stopButton);
    layout.addWidget(&button1);
    layout.addWidget(&button2);
    layout.addWidget(&button3);
    layout.addWidget(&button4);
    w.setLayout(&layout);


    QMessageBox box(&w);
    box.addButton(QMessageBox::Ok);
    box.setText(QObject::tr("打断了,现在是is"));
    box.setIcon(QMessageBox::Information);

    s0.addTransition(&button,SIGNAL(clicked()),&s);

    s1.addTransition(&button,SIGNAL(clicked()),&s2);//s1为这个过渡的始状态,s2为末状态
    
    //八个过渡,可是应为选择的是2个属性,所以是2+2和2*2一样,但是这样是线性的
    //比如按钮3被点击,s111和s122都是activity的同时响应,平行的
    s111.addTransition(&button3,SIGNAL(clicked()),&s112);//a1->a2
    s111.addTransition(&button4,SIGNAL(clicked()),&s112);
    s112.addTransition(&button1,SIGNAL(clicked()),&s111);//a2->a1
    s112.addTransition(&button2,SIGNAL(clicked()),&s111);

    s121.addTransition(&button2,SIGNAL(clicked()),&s122);//b1->b2
    s121.addTransition(&button4,SIGNAL(clicked()),&s122);
    s122.addTransition(&button1,SIGNAL(clicked()),&s121);//b2->b1
    s122.addTransition(&button3,SIGNAL(clicked()),&s121);

    s2.addTransition(&button,SIGNAL(clicked()),&s3);
    s3.addTransition(&button,SIGNAL(clicked()),&s1);

    //每个状态进入时,设置指定对象指定项指定的值
    s1.assignProperty(&showLabel,"text","当前:s1");
    s2.assignProperty(&showLabel,"text","当前:s2");
    s3.assignProperty(&showLabel,"text","当前:s3");

    //同时进入,而且这个是原子操作,不会被事件打断,但是是队列的,因为状态机是单线程的
    s11.assignProperty(&showLabel,"text","s11");
    s12.assignProperty(&showLabel2,"text","s12");

    s111.assignProperty(&showLabel,"text","a1");
    s112.assignProperty(&showLabel,"text","a2");
    s121.assignProperty(&showLabel2,"text","b1");
    s122.assignProperty(&showLabel2,"text","b2");



    //给每个状态添加过渡
    s.addTransition(&qButton,SIGNAL(clicked()),&fState);//s -- > finalState,但是在这组内的状态对于这个过渡可以覆盖

    //s2.addTransition(&qButton,SIGNAL(clicked()),&s3);//如果添加这一个句,那么在s2点击qButton按钮
    //就不会退出,只是转向了s3

    s.addTransition(&iButton,SIGNAL(clicked()),&is);

    is.addTransition(&sh);


    QObject::connect(&is,SIGNAL(entered()),&box,SLOT(exec()));




    //也可能重写 QAbstractState::onEntry()和QAbstractState::onExit()函数
    //在UML的状态图中,每个状态在进入状态和离开状态的时候都会进行相关的操作
    //这个可以通过这两个信号来解决,也可通过继承来重写上述的两个函数
    QObject::connect(&s3,SIGNAL(entered()),&w,SLOT(showMinimized()));
    QObject::connect(&s3,SIGNAL(exited()),&w,SLOT(showMaximized()));
    QObject::connect(&sMachine,SIGNAL(finished()),&app,SLOT(quit()));

    QObject::connect(&startButton,SIGNAL(clicked()),&sMachine,SLOT(start()));
    QObject::connect(&stopButton,SIGNAL(clicked()),&sMachine,SLOT(stop()));

    sMachine.addState(&s0);
    sMachine.addState(&s);//对于状态机只是添加顶层的状态
    // sMachine.addState(&s1);
    // sMachine.addState(&s2);
    // sMachine.addState(&s3);
    sMachine.addState(&fState);
    sMachine.addState(&is);


    //设置状态机的初始状态
    //sMachine.setInitialState(&s1);
    sMachine.setInitialState(&s0);//对于状态机的初始化,只是使用顶层的状态初始化,所以每个顶层如果是
    //一组状态,那么就要指定这组状态的初始化状态
    w.show();
    //状态机开启
    //   sMachine.start();

    //可以通过给状态分组来实现状态过渡的共享,比如我们希望在任何状态下我们都能够退出,
    //那么这个退出状态就是比其他的状态具有高的状态层次,那么我们就要将其他的状态封装在
    //合适的与退出状态同层次的一个高阶的状态层次中
    return app.exec();
}
点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
3年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Stella981 Stella981
3年前
KVM调整cpu和内存
一.修改kvm虚拟机的配置1、virsheditcentos7找到“memory”和“vcpu”标签,将<namecentos7</name<uuid2220a6d1a36a4fbb8523e078b3dfe795</uuid
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
UDT协议实现分析——UDT初始化和销毁
UDT协议是一个用于在高速Internet上传输大量数据的基于UDP的可靠传输协议。我们可以将UDT协议的实现看作一个比较复杂的状态机。更准确的说,是一个主状态机,外加多个子状态机。主状态机是指协议实现中全局唯一、全局共享的状态与数据结构,主要对应于CUDTUnited类。子状态机则是对于一次UDT连接或一个Listening的UDTServer的抽象
Wesley13 Wesley13
3年前
FPGA 高手养成记
来源:公众号【ZYNQ】ID  :FreeZynq整理:李肖遥本文目录1.前言2.状态机简介3.状态机分类Mealy型状态机Moore型状态机4.状态机描述一段式状态机二段式状态机三段式状态机
京东云开发者 京东云开发者
10个月前
玩转Spring状态机 | 京东云技术团队
说起Spring状态机,大家很容易联想到这个状态机和设计模式中状态模式的区别是啥呢?没错,Spring状态机就是状态模式的一种实现,在介绍Spring状态机之前,让我们来看看设计模式中的状态模式。1\.状态模式状态模式的定义如下:状态模式(StatePat
Python进阶者 Python进阶者
9个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这
京东云开发者 京东云开发者
4个月前
玩转Spring状态机
说起Spring状态机,大家很容易联想到这个状态机和设计模式中状态模式的区别是啥呢?没错,Spring状态机就是状态模式的一种实现,在介绍Spring状态机之前,让我们来看看设计模式中的状态模式。1.状态模式状态模式的定义如下:状态模式(StatePatt