在现实生活中,我们在不同的状态,对于相同的事,会有不同的反应,就拿天气对上班的影响。可以例举下图:
天气 | 上班方式 |
---|---|
晴朗 | 走路 |
下雨 | 打伞上班 |
台风 | 不上班 |
还有,我们学硬件时的点亮Led,也会有以下操作:
源状态 | 目标状态 | 事件 |
---|---|---|
常亮(Light) | 熄灭(close) | close |
常亮(Light) | 闪烁 (Blink) | blink |
熄灭(Close ) | 常亮(Light) | light |
熄灭(Close ) | 闪烁(Blink) | blink |
闪烁(Blink) | 熄灭(close) | close |
闪烁(Blink) | 常亮(Light) | light |
按照上图,我们可以看出:
当发出 close 事件时,Led 有可能处于不同状态,如常亮,或者闪烁状态,这里面还是省略了,如果目标状态与当前状态一样应该要怎么办。在下面代码中实现了。
这里将演示如何实现上述表格的状态,视频如下:
http://mpvideo.qpic.cn/0bc32iaegaaanuangw6igvqvbuwdipjaaqya.f10002.mp4?
其中主要的代码如下:
1. LedController 控制类 的头文件
以下主要看注释部分:
代码语言:javascript复制class LedController : public QObject
{
Q_OBJECT
public:
typedef enum {
LIGHT,
BLINK,
CLOSE
}eLedState,eLedCmd; // Led 的状态枚举
typedef struct {
eLedCmd cmd;
QString msg;
}eLedEvent;
explicit LedController(QObject *parent = nullptr);
explicit LedController(Ui::Widget *ui, QObject *parent = nullptr);
private:
eLedState m_ledState = CLOSE; // 记录 Led 状态
QQueue<eLedEvent> m_cmdQueue;
bool m_handleMessage = false;
QTimer *timer;
Ui::Widget *m_ui;
QPixmap *ledLightPic;
QPixmap *ledClosePic;
signals:
void controlLedState(eLedEvent enent);
...
...
}
2. 根据当前 Led 状态进行转换(在控制类 的源文件中)
代码语言:javascript复制void LedController::onHandleLedEvent()
{
if (!m_cmdQueue.empty()) {
//说明正在处理信息,获取事件
m_handleMessage = true;
eLedEvent ledEvent = m_cmdQueue.dequeue();
QString msg = ledEvent.msg;
//根据 Led 状态散转
switch(m_ledState)
{
case LIGHT: //当前 Led 已经被点亮
switch (ledEvent.cmd)
{
case LIGHT:
qDebug() << "当前 Led 已经为点亮状态";
break;
case BLINK:
qDebug() << "当前 Led 为点亮状态, 转换为闪烁状态";
m_ledState = BLINK;
startBlink(1000);
break;
case CLOSE:
qDebug() << "当前 Led 为点亮状态, 转换为关闭状态";
m_ledState = CLOSE;
closeLed();
break;
default:
break;
}
break;
case BLINK: //当前 Led 已经是闪烁状态
switch (ledEvent.cmd)
{
case LIGHT:
qDebug() << "当前 Led 为闪烁状态,转换为点亮状态";
m_ledState = LIGHT;
stopBlink();
lightLed();
break;
case BLINK:
qDebug() << "当前 Led 为闪烁状态,修改闪烁间隔为 " msg " ms";
startBlink(msg.toInt());
m_ledState = BLINK;
break;
case CLOSE:
qDebug() << "当前 Led 为闪烁状态,转换为关闭状态";
m_ledState = CLOSE;
stopBlink();
closeLed();
break;
default:
break;
}
break;
case CLOSE: //当前 Led 已经是关闭状态
switch (ledEvent.cmd)
{
case LIGHT:
qDebug() << "当前 Led 为关闭状态,转换为点亮状态";
m_ledState = LIGHT;
lightLed();
break;
case BLINK:
qDebug() << "当前 Led 为关闭状态,转换为闪烁状态,间隔为 " msg " ms";
m_ledState = BLINK;
startBlink(msg.toInt());
break;
case CLOSE:
qDebug() << "当前 Led 已经为关闭状态";
break;
default:
break;
}
break;
}
m_handleMessage = false;
}
}
3. 最终结果如开头视频所示
4. 源代码
后台回复:状态机
如果你还是没看懂,建议把代码运行跑跑看。