Как изменить состояние самого объекта состояния не снаружи?

    class ListenState : public QState
    {
    public:
        ListenState();
        ~ListenState();

    signals:
        void nextState();

    public slots:
        void getSettings();
    };

Файл cpp

ListenState::ListenState()
{
    qDebug() << "Entering ListenState";
}

ListenState::~ListenState()
{
    qDebug() << "Leaving ListenState";
}

void ListenState::getSettings()
{
    Commands cmd;

    cmd.getSettings();

    emit exited( QEvent::None ); // i want to change state now
}

Что я хочу сделать, это когда getSettings() называется, я хочу изменить состояние на следующее. Я думал, что emit exited() но это не строит. Я пытался создать свой собственный сигнал nextState() но это не компилируется, если я излучаю в этой функции.

С кодом выше ошибка:

ListenState.cpp: 23: ошибка: C2664: "QAbstractState::exited": невозможно преобразовать параметр 1 из "QEvent::Type" в "QAbstractState::QPrivateSignal". Не доступен оператор преобразования, определенный пользователем, который может выполнить это преобразование, или оператор не может быть вызван

Если я испускаю свой собственный сигнал с emit nextState(); ошибка:

ListenState.obj: -1: ошибка: LNK2001: неразрешенный внешний символ "public: void __thiscall ListenState::nextState(void)" (? NextState@ListenState@@QAEXXZ)

Есть ли способ вызвать переход из одного состояния в другое, когда я нахожусь в исходном состоянии?

1 ответ

Во-первых, время жизни состояния очень мало связано с тем, когда оно входит или выходит. Состояния обычно существуют до тех пор, пока существует конечный автомат, или они могут создаваться и уничтожаться на лету. Вы подключаете конструктор и деструктор состояния, ожидая, что они будут вызваны при входе или выходе из состояния. Это не вариант.

Чтобы проверить, когда состояние было введено или вышло, вы можете использовать следующее:

void exposeStateTransitions(QState * state, QString name) {
  if (name.isEmpty()) name = state->objectName();
  QObject::connect(state, &QState::entered, []{
    qDebug() << "state" << name << "was entered";
  });
  QObject::connect(state, &QState::exited, []{
    qDebug() << "state" << name << "was exited";
  });
}

Во-вторых, состояния могут быть изменены только с помощью объектов перехода. Вам нужно создать объект перехода для желаемого перехода и предоставить сигнал или событие для его запуска:

class ListenState : public QState {
  Q_OBJECT
  QSignalTransition m_transition;
  Q_SIGNAL void settingsTransition();
public:
  ListenState(QState * settingsTarget, QState * parent = 0) : 
    QState(parent), m_transition(this, SIGNAL(settingsTransition())
  {
    m_transition.setTargetState(settingsTarget);
    addTransition(&m_transition);
  }
  void getSettings() {
    ...
    emit settingsTransition();
  }
};

При желании вы также можете запустить переход на лету:

class ListenState : public QState {
  Q_OBJECT
  QSignalTransition m_transition;
  Q_SIGNAL void settingsTransition();
public:
  ListenState(QState * parent = 0) : 
    QState(parent), m_transition(this, SIGNAL(settingsTransition())
  {
    addTransition(&m_transition);
  }
  void getSettings(QState * target) {
    ...
    m_transition.setTargetState(target);
    emit settingsTransition();
  }
};

Вы можете использовать события вместо сигналов:

class ListenState : public QState {
  QEventTransition m_transition;
public:
  ListenState(QState * parent = 0) : 
    QState(parent), m_transition(this, QEvent::Leave) {
    addTransition(&m_transition);
  }
  void getSettings(QState * target) {
    ...
    m_transition->setTargetState(target);
    QCoreApplication::postEvent(this, new QEvent(QEvent::Leave));
  }
};
Другие вопросы по тегам