Qt状态机QStateMachine

发布于:2025-05-27 ⋅ 阅读:(90) ⋅ 点赞:(0)

QStateMachine

QState 提供了一种强大且灵活的方式来表示状态机中的状态,通过与状态机类(QStateMachine)和转换类(QSignalTransition, QEventTransition)结合,可以实现复杂的状态逻辑和用户交互。合理使用嵌套状态机、信号转换、动作与动画、历史状态和定时器事件等功能,可以增强应用的交互性和视觉效果。在实际应用中,通过优化状态逻辑和转换规则,可以实现丰富和动态的状态管理功能。注意设置转换条件、信信号槽连接和事件处理逻辑,确保状态转换的正确性和高效性。结合其他 Qt 类和方法,可以实现更多高级功能和应用场景,提高应用的灵活性和可维护性。

官方文档参考:https://doc.qt.io/archives/qt-6.6/qtstatemachine-cpp-guide.html

Qt Class Hierarchy 类继承关系图 https://doc.qt.io/qt-6/hierarchy.html

案例 Demo: 上下班打卡

上下班打卡

#include <QStateMachine>
qmake: QT += statemachine
CMake: find_package(Qt6 REQUIRED COMPONENTS StateMachine)
target_link_libraries(mytarget PRIVATE Qt6::StateMachine)
// mainwindow.h
#include <QMainWindow>

QT_BEGIN_NAMESPACE
namespace Ui{class MainWindow;}
QT_END_NAMESPACE

class QStateMachine;
class MainWindow : public QMainWindow {
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
signals:
    void isWorkDay(bool);
    void inOfficeArea(bool);
    void shouldRemind(bool);
    void remindFinished();
private:
    void init();
private slots:
    void checkConditions();
private:
    Ui::MainWindow *ui;
    QStateMachine *machine;
    QTimer *checkTimer;
};

#endif // MAINWINDOW_H
// mainwindow.cpp
#include <QStateMachine>      // QT += statemachine or Qt6::StateMachine
#include <QTimer>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
    , machine(new QStateMachine(this))
{
    ui->setupUi(this);
    init();
}
void MainWindow::init()
{ // 1.创建状态: 空闲->工作日->在办公区域->提醒
    //若对状态进行分组:创建状态时指定正确的父状态
    QState *idleState = new QState(machine);
    QState *workdayState = new QState(machine);
    QState *locationState = new QState(machine);
    QState *remindState = new QState(machine);
    machine->setInitialState(idleState);

    //2. 设置状态转换
    idleState->addTransition(this, &MainWindow::isWorkDay, workdayState);
    workdayState->addTransition(this, &MainWindow::inOfficeArea, locationState);
    locationState->addTransition(this, &MainWindow::shouldRemind, remindState);
    remindState->addTransition(this, &MainWindow::remindFinished, idleState);

    // 比如remindState状态进入时的操作
    connect(remindState, &QState::entered, this,[=](){
        ui->label->setText("打卡提醒, 请及时打卡!");
        ui->pushButton->setEnabled(true);
        emit remindFinished();
    });
    machine->start();

    // 设置定时检查--纯模拟
    checkTimer = new QTimer(this);
    connect(checkTimer, &QTimer::timeout, this, &MainWindow::checkConditions);
    checkTimer->start(3000);
    //打卡按钮
    connect(ui->pushButton,&QPushButton::clicked,this,[=](){
        auto t=ui->timeEdit->time();
        QString text;
        if(t >= QTime(6,45) && t <= QTime(9,30)) text = "上班";
        else if(t > QTime(9,30) && t < QTime(12,0)) text = "上班迟到";
        else if(t > QTime(13,30) &&  t < QTime(18,0) )text = "提前下班";
        else if(t >= QTime(18,0)) text = "下班";
        ui->label->setText(t.toString() + text + " 打卡成功");
    });
}

void MainWindow::checkConditions()
{
    QTime t = ui->timeEdit->time();
    ui->pushButton->setEnabled(false);
    // 1.判断工作日 QDate::currentDate().dayOfWeek() <= 5; // 周一到周五
    bool workday = ui->ckBankHoliday->isChecked() ? false :
                   ui->ckWorkDay->isChecked() ? true : false;
    emit isWorkDay(workday);
    if(!workday){
        ui->label->setText(t.toString() + " 假期,无需打卡");
        return;
    }

    // 2.判断位置 (实际用QGeoPositionInfoSource)
    bool inOffice = ui->ckInOfficeArea->isChecked(); // 在办公区域
    emit inOfficeArea(inOffice);
    if(!inOffice){
        ui->label->setText(t.toString() + " 不在办公区域,无法打卡");
        return;
    }
    //3.上班前/下班后提醒打卡
    bool isWorkTime = (t >= QTime(6,45) && t <= QTime(23,59));
    if(!isWorkTime){
        ui->label->setText(t.toString() + " 无法打卡\n打卡时间 6:45-9:30  18:00-22:30");
        return;
    }
    emit shouldRemind(isWorkTime);
}

其它大佬

https://blog.csdn.net/weixin_43510208/article/details/147960966


网站公告

今日签到

点亮在社区的每一天
去签到