使用状态机可以很方便的实现状态之间的切换,以及切换时的动作
一下是纯C++实现的状态机, 以及在QT中的切换效果
C++#include <iostream>
#include <unordered_map>
class StateMachine {
public:
StateMachine() : currentStateName("") {}
void addState(const std::string& name, const std::function<void()>& stateFunction) {
states[name] = stateFunction;
}
void addTransition(const std::string& from, const std::string& to, const std::function<bool()>& transitionFunction) {
transitions[from][to] = transitionFunction;
}
void start(const std::string& initialState) {
currentStateName = initialState;
if (states.find(currentStateName) != states.end()) {
states[currentStateName]();
} else {
std::cerr << "Invalid initial state: " << initialState << std::endl;
}
}
void triggerTransition() {
if (transitions.find(currentStateName) != transitions.end()) {
for (const auto& entry : transitions[currentStateName]) {
if (entry.second()) {
nextStateName = entry.first;
return;
}
}
}
nextStateName = ""; // No valid transition found
}
void updateState() {
if (!nextStateName.empty()) {
currentStateName = nextStateName;
if (states.find(currentStateName) != states.end()) {
states[currentStateName]();
} else {
std::cerr << "Invalid state: " << currentStateName << std::endl;
}
nextStateName = "";
}
}
std::string getCurrentState() const {
return currentStateName;
}
std::string getNextState() const {
return nextStateName;
}
private:
std::unordered_map<std::string, std::function<void()>> states;
std::unordered_map<std::string, std::unordered_map<std::string, std::function<bool()>>> transitions;
std::string currentStateName;
std::string nextStateName;
};
QT 代码
头文件
C++#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QPropertyAnimation>
#include <QMainWindow>
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private slots:
void on_pushButton_clicked();
private slots:
void onAnimationFinished();
private:
Ui::MainWindow *ui;
StateMachine stateMachine;
QPropertyAnimation* positionAnimation;
bool positionAnimationing {false};
};
#endif // MAINWINDOW_H
CPP
C++#include "mainwindow.h"
#include "ui_mainwindow.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
// 在 MainWindow 的构造函数中初始化 positionAnimation
positionAnimation = new QPropertyAnimation(ui->stateobj, "pos", this);
positionAnimation->setDuration(400); // 设置动画持续时间为500毫秒
positionAnimation->setEasingCurve(QEasingCurve::InOutBack);
connect(positionAnimation, &QPropertyAnimation::finished, this, &MainWindow::onAnimationFinished);
stateMachine.addState("StateA", [&]() { ui->stateobj->setText("State A");std::cout << "State A" << std::endl; });
stateMachine.addState("StateB", [&]() { ui->stateobj->setText("State B");std::cout << "State B" << std::endl; });
stateMachine.addState("StateC", [&]() { ui->stateobj->setText("State C");std::cout << "State C" << std::endl; });
stateMachine.addTransition("StateA", "StateB", [&]() {
std::cout << "Transition from A to B" << std::endl;
int x = 0;
int y = height() / 2 - ui->stateobj->height() / 2;
positionAnimation->setEndValue(QPoint(x, y)); // 左边中间位置
return true; // Allow transition
});
stateMachine.addTransition("StateB", "StateC", [&]() {
std::cout << "Transition from B to C" << std::endl;
int x = 0;
int y = height() - ui->stateobj->height();
positionAnimation->setEndValue(QPoint(x, y)); // 左下角
return true; // Allow transition
});
stateMachine.addTransition("StateC", "StateA", [&]() {
std::cout << "Transition from C to A" << std::endl;
positionAnimation->setEndValue(QPoint(0, 0));
return true; // Allow transition
});
stateMachine.start("StateA");
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_pushButton_clicked()
{
if(!positionAnimationing)
{
stateMachine.triggerTransition();
if (!stateMachine.getNextState().empty()) {
stateMachine.updateState();
}
// 启动动画
positionAnimation->start();
positionAnimationing = true;
}
}
void MainWindow::onAnimationFinished() {
// 在动画结束时执行的操作
positionAnimationing = false;
}
效果
本文作者:beiklive
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!