Qt之浅析状态机QState

版权声明:本文为博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/dongfenghuojian/article/details/78187131

Qt之浅析状态机QState

一、状态机,百度百科上分为四部分:现态、条件(事件)、动作和次态。状态机是做界面逻辑常用的方法。

二、Qt上的状态机有关的常用类:QState、QStateMachine、QFinalState等。

三、设备安装程序中界面的逻辑复杂的时候,用状态机会简化程序。例如看下面这个情景。有三个按钮,第一个是“全选”,按下去变为“取消全选”;第二个是“选择已安装”,按下去变为“取消选择已安装”;第三个是“选择未安装”,按下去变为“取消选择未安装”。这三个按钮的作用效果跟按钮下方的TreeView中的设备相关。当按下第一个按钮时,选中所有的设备,按钮为按下状态,图标改变,按钮上的字也响应变成“取消全选”,同时第二个、第三个按钮也会按下,图标、字也相应改变。第二个、第三个按钮同时按下,第一个按钮无论之前是什么状态都会变为按下状态,第二个、第三个按钮只要有一个没有按下,第一个按钮就会弹起。在TreeView中,手动选择设备也会有类似的效果,当选中所有设备,第一个按钮即使没有鼠标点击也会变成按下状态,这也适用于第二个、第三个按钮。这个逻辑关系复杂,如果用标志位需要写很多判断。可以用状态机实现。
(1)每个按钮单独连接槽,对应各自的功能;
(2)TreeView每次有设备选择状态改变时,判断是否全选、是否选中了全部已安装设备、是否选择全部未安装、是否有一些设备在全选或选择已安装或者选择未安装状态下取消了选择,并根据具体情况发送响应的信号。总共定义了6种信号。
(3)三个按钮定义状态机,s1、s2、s3分别代表三个按钮状态。s11、s12代表一号按钮弹起和按下两种状态,并作为s1的子状态,子状态模式为默认模式(可能是ExclusiveStates)。S21、s22是s2的子状态,s31、s32是s3的子状态。s1、s2、s3是s的子状态,模式为平行模式(QState::ParallelStates)。S加入QStateMachine。以下是状态关系图。

四、以下是代码示意:

void OpenDeviceDlg::setupStateMachine()
{
    //**********状态机--ltx--17-7-11
    //**********1--up;2--down;3--invisible
    //**********s1--全选按钮;s2--选择已安装按钮;s3--选择未安装按钮

    //**********定义所有的状态State
    QState *s = new QState(QState::ParallelStates);
    QState *s1 = new QState(s);
    QState *s2 = new QState(s);
    QState *s3 = new QState(s);

    QState *s11 = new QState(s1);
    QState *s12 = new QState(s1);
    QState *s13 = new QState(s1);
    s1->setInitialState(s11);
    QState *s21 = new QState(s2);
    QState *s22 = new QState(s2);
    QState *s23 = new QState(s2);
    s2->setInitialState(s21);
    QState *s31 = new QState(s3);
    QState *s32 = new QState(s3);
    QState *s33 = new QState(s3);
    s3->setInitialState(s31);

    //**********定义所有的Transition
    s11->addTransition(pModel, SIGNAL(selectedAll()), s12);
    s13->addTransition(pModel, SIGNAL(selectedAll()), s12);
    s12->addTransition(pModel, SIGNAL(unselectedAll()), s11);
    s13->addTransition(pModel, SIGNAL(unselectedAll()), s11);
    s11->addTransition(pModel, SIGNAL(emptiedAll()), s13);
    s12->addTransition(pModel, SIGNAL(emptiedAll()), s13);

    s21->addTransition(pModel, SIGNAL(selectedInstalled()), s22);
    s23->addTransition(pModel, SIGNAL(selectedInstalled()), s22);
    s22->addTransition(pModel, SIGNAL(unselectedInstalled()), s21);
    s23->addTransition(pModel, SIGNAL(unselectedInstalled()), s21);
    s21->addTransition(pModel, SIGNAL(emptiedInstalled()), s23);
    s22->addTransition(pModel, SIGNAL(emptiedInstalled()), s23);

    s31->addTransition(pModel, SIGNAL(selectedNotinstalled()), s32);
    s33->addTransition(pModel, SIGNAL(selectedNotinstalled()), s32);
    s32->addTransition(pModel, SIGNAL(unselectedNotinstalled()), s31);
    s33->addTransition(pModel, SIGNAL(unselectedNotinstalled()), s31);
    s31->addTransition(pModel, SIGNAL(emptiedNotinstalled()), s33);
    s32->addTransition(pModel, SIGNAL(emptiedNotinstalled()), s33);

    QIcon checkblank = QIcon(":/images/images/checkblank.png");
    QIcon checkright = QIcon(":/images/images/checkright.png");

    //**********配置属性
    //**********按钮1
    s11->assignProperty(ui.pushButtonSelectAll, "visible", true);
    s11->assignProperty(ui.pushButtonSelectAll, "text", tr("All"));
    s11->assignProperty(ui.pushButtonSelectAll, "checked", false);
    s11->assignProperty(ui.pushButtonSelectAll, "icon", checkblank);

    s12->assignProperty(ui.pushButtonSelectAll, "visible", true);
    s12->assignProperty(ui.pushButtonSelectAll, "text", tr("cAll"));
    s12->assignProperty(ui.pushButtonSelectAll, "checked", true);
    s12->assignProperty(ui.pushButtonSelectAll, "icon", checkright);

    s13->assignProperty(ui.pushButtonSelectAll, "visible", false);
    //**********按钮2
    s21->assignProperty(ui.pushButtonHasInstalled, "visible", true);
    s21->assignProperty(ui.pushButtonHasInstalled, "text", tr("Inst"));
    s21->assignProperty(ui.pushButtonHasInstalled, "checked", false);
    s21->assignProperty(ui.pushButtonHasInstalled, "icon", checkblank);

    s22->assignProperty(ui.pushButtonHasInstalled, "visible", true);
    s22->assignProperty(ui.pushButtonHasInstalled, "text", tr("cInst"));
    s22->assignProperty(ui.pushButtonHasInstalled, "checked", true);
    s22->assignProperty(ui.pushButtonHasInstalled, "icon", checkright);

    s23->assignProperty(ui.pushButtonHasInstalled, "visible", false);
    //**********按钮3
    s31->assignProperty(ui.pushButtonNotInstalled, "visible", true);
    s31->assignProperty(ui.pushButtonNotInstalled, "text", tr("NInst"));
    s31->assignProperty(ui.pushButtonNotInstalled, "checked", false);
    s31->assignProperty(ui.pushButtonNotInstalled, "icon", checkblank);

    s32->assignProperty(ui.pushButtonNotInstalled, "visible", true);
    s32->assignProperty(ui.pushButtonNotInstalled, "text", tr("cNInst"));
    s32->assignProperty(ui.pushButtonNotInstalled, "checked", true);
    s32->assignProperty(ui.pushButtonNotInstalled, "icon", checkright);

    s33->assignProperty(ui.pushButtonNotInstalled, "visible", false);

    machine.addState(s);
    machine.setInitialState(s);
    machine.start();

}
展开阅读全文

Qt状态机QState如何接收QKeyEvent?

06-04

// ----------------------------GraphicsScene.h ---------------------------------//rnclass PlayState;rnclass GraphicsScene : public QGraphicsScenernrn Q_OBJECTrnpublic:rn GraphicsScene(int x, int y, int width, int height);rnrnsignals:rnrnprivate slots:rnrnprotected:rn void keyPressEvent(QKeyEvent *event);rn void keyReleaseEvent(QKeyEvent *event);rnprivate:rnrn PlayState *playState;rn QFinalState *final;rn bool playing;rn friend class PlayState;rn;rnrn// ----------------------------GraphicsScene.cpp 省略其它函数 ---------------------------------//rnrnvoid GraphicsScene::keyPressEvent(QKeyEvent *event)rnrn if(playing)rn playState->keyPressEvent(event->key());rnrnrnvoid GraphicsScene::keyReleaseEvent(QKeyEvent *event)rnrn if(playing)rn playState->keyReleaseEvent(event);rnrnrn// ----------------------------GraphicsScene.h ---------------------------------//rnclass PlayState : public QStaternrn Q_OBJECTrnpublic:rn PlayState(GraphicsScene *scene, QState *parent);rn ~PlayState();rn void keyPressEvent(QKeyEvent *event);rn void keyReleaseEvent(QKeyEvent *event);rnpublic slots:rnrnprotected:rn void onEntry(QEvent *);rn void onExit(QEvent *);rnprivate :rnrn GraphicsScene *scene;rn QStateMachine *machine;rn QState *parallelChild;rnrn KeyBall *keyballSpace;rn;rnrn// ----------------------------PlayState.cpp 省略其它函数 ---------------------------------//rnrnvoid PlayState::keyPressEvent(QKeyEvent *event)rnrn switch(event->key())rn rn case Qt::Key_Space:rn rn keyballSpace->presse();rn rn break;rn default:rn break;rn rnrnrnvoid GraphicsScene::keyReleaseEvent(QKeyEvent *event)rnrn switch(event->key())rn rn case Qt::Key_Space:rn rn keyballSpace->release();rn rn break;rn default:rn break;rn rnrnrnrnGraphicsScene可以直接重写keyPressEvent(QKeyEvent *event)和keyReleaseEvent(QKeyEvent *event)rn我在GraphicsScene的keyPressEvent和keyReleaseEvent中调用PlayState中的keyPressEvent和keyReleaseEvent(PlayState中的keyPressEvent和keyReleaseEvent是自己定义的函数,父类没有这类函数),执行到keyballSpace->release()这句便出错,keyballSpace已newrn想问下是否有人和我出现类似的情况,或者是否有更好的办法在QState中接收到事件? 论坛

没有更多推荐了,返回首页