Qt利用QState状态机实现控件互斥操作详解

软件发布|下载排行|最新软件

当前位置:首页IT学院IT技术

Qt利用QState状态机实现控件互斥操作详解

中国好公民st   2022-12-05 我要评论

最近学习了QState状态机功能,今天为大家分享下如何实现按钮的互斥效果吧。

首先,看一下实现效果~

功能讲解

开发环境:VS2017 + Qt5.14.2

该例子实现了类似于QRadioButton的效果。

从QtDesigner中拖出了三个QPushButton控件,分别是:ui.btn1、ui.btn2、ui.btn3,每个按钮都有对应的状态,分别是:state1、state2、state3

选中后背景颜色值是:QColor(255,182,193)、未选中的背景颜色值是:QColor(255,239,213);

设置步骤

1:设置btn1对应的状态信息

QState *state1 = new QState;
state1->assignProperty(ui.btn1, "text", QStringLiteral("1选中"));
state1->assignProperty(ui.btn1, "styleSheet", "background-color:rgb(255,182,193)");
state1->assignProperty(ui.btn2, "text", QStringLiteral("2"));
state1->assignProperty(ui.btn2, "styleSheet", "background-color:rgb(255,239,213)");
state1->assignProperty(ui.btn3, "text", QStringLiteral("3"));
state1->assignProperty(ui.btn3, "styleSheet", "background-color:rgb(255,239,213)");

代码讲解使用QState::assignProperty,指示此状态在进入状态时将具有给定对象的给定名称的属性设置为给定值。

通俗来说,就是响应状态需要让哪些按钮做什么样的操作。

在响应state1状态时,btn1的文字变成了"1选中",背景颜色也发生了变化,同理,state2、state3也是如此。

2:设置btn2对应的状态信息

QState *state2 = new QState;
state2->assignProperty(ui.btn1, "text", QStringLiteral("1"));
state2->assignProperty(ui.btn1, "styleSheet", "background-color:rgb(255,239,213)");
state2->assignProperty(ui.btn2, "text", QStringLiteral("2选中"));
state2->assignProperty(ui.btn2, "styleSheet", "background-color:rgb(255,182,193)");
state2->assignProperty(ui.btn3, "text", QStringLiteral("3"));
state2->assignProperty(ui.btn3, "styleSheet", "background-color:rgb(255,239,213)");

3:设置btn3对应的状态信息

QState *state3 = new QState;
state3->assignProperty(ui.btn1, "text", QStringLiteral("1"));
state3->assignProperty(ui.btn1, "styleSheet", "background-color:rgb(255,239,213)");
state3->assignProperty(ui.btn2, "text", QStringLiteral("2"));
state3->assignProperty(ui.btn2, "styleSheet", "background-color:rgb(255,239,213)");
state3->assignProperty(ui.btn3, "text", QStringLiteral("3选中"));
state3->assignProperty(ui.btn3, "styleSheet", "background-color:rgb(255,182,193)");

4:设置停止状态

当设置了所有控件对应的状态后,最后需要设置停止状态。停止状态是一个单独的状态类:QFinalState。

QFinalState *stateFinal = new QFinalState;

5:数据绑定

每个单独的状态设置完成后,那么该如何对状态以及按钮做绑定呢?

state1->addTransition(ui.btn1, &QPushButton::clicked, state1);
state2->addTransition(ui.btn2, &QPushButton::clicked, state2);
state3->addTransition(ui.btn3, &QPushButton::clicked, state3);

6:将所有的状态添加到状态机QStateMachine中

QStateMachine *pMachine = new QStateMachine;
pMachine->addState(state1);
pMachine->addState(state2);
pMachine->addState(state3);
pMachine->addState(stateFinal);

7:设置初始化状态

上述工作完成后,必须要给状态机设置初始状态,并且状态必须是这个状态的子状态。

pMachine->setInitialState(state1);

8:开始运行状态

pMachine->start();

好了,根据上述代码,进行调试运行试试?

结果发现,无论点击哪个按钮,按钮都没有反应,原因出到哪里呢?

答:错误是出在了第5步,当前状态是无法绑定自己的,那么该如何实现这种互斥?

对需要进行控件绑定的状态:stat1、state2、state3,设置一个父状态,由父状态来分配数据绑定就可以实现啦。

修改方案

1:创建父状态

QState *stateParent = new QState;

2:每个状态设置父状态

对state1、state2、state3的构造函数中,分别继承自stateParent,修改如下:

QState *state1 = new QState(stateParent);
QState *state2 = new QState(stateParent);
QState *state3 = new QState(stateParent);

3:数据绑定修改

由父状态进行分配状态对应,修改如下:

stateParent->addTransition(ui.btn1, &QPushButton::clicked, state1);
stateParent->addTransition(ui.btn2, &QPushButton::clicked, state2);
stateParent->addTransition(ui.btn3, &QPushButton::clicked, state3);
QFinalState *stateFinal = new QFinalState(stateParent);

并且,初始化父状态的初始子状态

stateParent->setInitialState(state1);

4:状态机数据绑定

此时,不需要将state1、state2、state3直接绑定到pMachine中了,而是将stateParent绑定到pMachine中。

并且,设置状态机pMachine的初始状态是stateParent。

经过如此修改后,调试代码发现,可以实现按钮的互斥效果了,也就是文章开始的动画效果。

在不使用状态时,使用stateFinal进行销毁就可以了。比如在响应关闭按钮时,可以做结束处理

stateParent->addTransition(ui.btnExit, &QPushButton::clicked, stateFinal);

下面贴出完整代码

今日份分享就到这里了~

Copyright 2022 版权所有 软件发布 访问手机版

声明:所有软件和文章来自软件开发商或者作者 如有异议 请与本站联系 联系我们