QT StateMachine添加状态切换处理函数

首先是简单的状态机使用。状态机里面包含不同的状态,状态之间可以切换。状态机的类是QStateMachine。 状态的类是QState。 在使用之前,需要在QT的pro配置文件中添加QT += statemachine。

先声明状态机和状态。

QStateMachine machine;
QState *stop;
QState *running;
QState *pause;

然后再实现:
stop = new QState;
running = new QState;
pause = new Qstate;

将状态添加到状态机:
machine.addState(stop);
machine.addState(running);
machine.addState(pause);

状态机里有多个状态,但不知道从哪里开始执行。我们需要指定一个初始的状态。
machine.setInitialState(stop);

状态之前需要切换,从一个状态变成另一个状态。我们需要告诉程序状态之间的切换关系,还有在什么状态下切换。
在按钮按下时,从stop切换到running状态
stop->addTransition(ui->changeStateButton, &QPushButton::clicked, running);
在按钮按下时,从running切换到pause状态
running->addTransition(ui->changeStateButton, &QPushButton::clicked, pause);
在按钮按下时,从pause切换到running状态
pause->addTransition(ui->changeStateButton, &QPushButton::clicked, running);

然后,我们告诉状态机开始执行
machine.start();

好了,简单状态机完成,在UI上添加标签来显示状态值,开始运行程序,点击按钮。

什么也没发生!因为状态切换时,没有伴随的效果,我们看不出状态发生了变化。下面我们为各个状态添加一些肉眼可见的行为。
这里将状态和标签的text属性绑定起来,标签会根据状态来变更属性的值(属性有多种,可以在对应控件的帮助文档里找到)。
stop->assignProperty(ui->stateLabel, "text", QString(tr("停止状态")));
running->assignProperty(ui->stateLabel, "text", QString(tr("运行状态")));
pause->assignProperty(ui->stateLabel, "text", QString(tr("暂停状态")));
运行如下:

状态切换关系如下图:

一个简单的状态机完成了。

代码如下:

头文件

#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QStateMachine>
#include <QState>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private:
    Ui::Widget *ui;
    QStateMachine machine;
    QState *stop;
    QState *running;
    QState *pause;
};
#endif // WIDGET_H

源文件

#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    stop = new QState;
    running = new QState;
    pause = new QState;
    machine.addState(stop);
    machine.addState(running);
    machine.addState(pause);
    machine.setInitialState(stop);
    stop->addTransition(ui->changeStateButton, &QPushButton::clicked, running);
    running->addTransition(ui->changeStateButton, &QPushButton::clicked, pause);
    pause->addTransition(ui->changeStateButton, &QPushButton::clicked, running);
  
    machine.start();
    stop->assignProperty(ui->stateLabel, "text", QString(tr("停止状态")));
    running->assignProperty(ui->stateLabel, "text", QString(tr("运行状态")));
    pause->assignProperty(ui->stateLabel, "text", QString(tr("暂停状态")));
}
Widget::~Widget()
{
    delete ui;
}

继续完善,状态切换可以有不同的操作出发,我们再增加一个状态复位按钮,让状态回到停止状态。

增加如下代码,注意第二个参数也可以采用这种格式。将运行或暂停状态切换回停止状态。
running->addTransition(ui->resumeButton, SIGNAL(clicked()), stop);
pause->addTransition(ui->resumeButton, SIGNAL(clicked()), stop);

假如这个状态切换伴随着其他操作比如歌曲的播放和暂停,那在按钮按下时,需要对应的操作。对于按钮来说,都是click状态,怎么知道是谁切换到谁呢?可以通过判断标签的属性来确定,但更好的办法是不同的状态切换时直接触发对应的处理。

将stop的addTransition改造一下。 addTransition添加的参数可以是QSignalTransition类。QSignalTransition在初始化时,设置上关联的控件和控件动作。然后通过 setTargetState设置成将要变成的状态,通过triggered信号,来绑定触发时对应的行为(这里添加了一个槽函数)。再用stop状态添加新创建的QSignalTransition,完成状态切换的设置。

这样在状态切换的同时,还会调用对应的处理函数。

QSignalTransition *stopTorunning = new QSignalTransition(ui->changeStateButton, &QPushButton::clicked);

stopTorunning->setTargetState(running);

connect(stopTorunning, SIGNAL(triggered()), this, SLOT(stopToRunningSlot()));

stop->addTransition(stopTorunning);

为了直观的显示调用,将UI修改如下:

槽函数的实现如下:

void Widget::stopToRunningSlot()
{
 ui->textBrowser->append(QString("停止到运行"));
}

运行一下程序

 

 将其他转换设置也作类似更改,得到如下程序:

代码如下:

头文件

#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QStateMachine>
#include <QState>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
private slots:
    void stopToRunningSlot();
    void runningToPauseSlot();
    void pauseToRunningSlot();
    void runningToStopSlot();
    void pauseToStopSlot();
private:
    Ui::Widget *ui;
    QStateMachine machine;
    QState *stop;
    QState *running;
    QState *pause;
};
#endif // WIDGET_H

源文件

#include "widget.h"
#include "ui_widget.h"
#include <QSignalTransition>
Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    stop = new QState;
    running = new QState;
    pause = new QState;
    machine.addState(stop);
    machine.addState(running);
    machine.addState(pause);
    machine.setInitialState(stop);
    //stop->addTransition(ui->changeStateButton, &QPushButton::clicked, running);
    QSignalTransition *stopTorunning = new QSignalTransition(ui->changeStateButton, &QPushButton::clicked);
    stopTorunning->setTargetState(running);
    connect(stopTorunning, SIGNAL(triggered()), this, SLOT(stopToRunningSlot()));
    stop->addTransition(stopTorunning);
    //running->addTransition(ui->changeStateButton, &QPushButton::clicked, pause);
    QSignalTransition *runningTopause = new QSignalTransition(ui->changeStateButton, &QPushButton::clicked);
    runningTopause->setTargetState(pause);
    connect(runningTopause, SIGNAL(triggered()), this, SLOT(runningToPauseSlot()));
    running->addTransition(runningTopause);
    //pause->addTransition(ui->changeStateButton, &QPushButton::clicked, running);
    QSignalTransition *pauseTorunning = new QSignalTransition(ui->changeStateButton, &QPushButton::clicked);
    pauseTorunning->setTargetState(running);
    connect(pauseTorunning, SIGNAL(triggered()), this, SLOT(pauseToRunningSlot()));
    pause->addTransition(pauseTorunning);
    //running->addTransition(ui->resumeButton, SIGNAL(clicked()), stop);
    QSignalTransition *runningTostop = new QSignalTransition(ui->resumeButton, &QPushButton::clicked);
    runningTostop->setTargetState(stop);
    connect(runningTostop, SIGNAL(triggered()), this, SLOT(runningToStopSlot()));
    running->addTransition(runningTostop);
    //pause->addTransition(ui->resumeButton, SIGNAL(clicked()), stop);
    QSignalTransition *pauseTostop = new QSignalTransition(ui->resumeButton, &QPushButton::clicked);
    pauseTostop->setTargetState(stop);
    connect(pauseTostop, SIGNAL(triggered()), this, SLOT(pauseToStopSlot()));
    pause->addTransition(pauseTostop);
    machine.start();
    stop->assignProperty(ui->stateLabel, "text", QString(tr("停止状态")));
    running->assignProperty(ui->stateLabel, "text", QString(tr("运行状态")));
    pause->assignProperty(ui->stateLabel, "text", QString(tr("暂停状态")));
}
Widget::~Widget()
{
    delete ui;
}
void Widget::stopToRunningSlot()
{
    ui->textBrowser->append(QString("停止到运行"));
}
void Widget::runningToPauseSlot()
{
    ui->textBrowser->append(QString("运行到暂停"));
}
void Widget::pauseToRunningSlot()
{
    ui->textBrowser->append(QString("暂停到运行"));
}
void Widget::runningToStopSlot()
{
    ui->textBrowser->append(QString("运行到停止"));
}
void Widget::pauseToStopSlot()
{
    ui->textBrowser->append(QString("暂停到停止"));
}

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值