首先是简单的状态机使用。状态机里面包含不同的状态,状态之间可以切换。状态机的类是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
- #include
- #include
- 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
- #include
- #include
- 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
- 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("暂停到停止"));
- }