QML: Как можно назначить состояние элемента при изменении состояния другого элемента? (Как я могу обойти ограничения штата назначения?) - PullRequest
0 голосов
/ 25 января 2020

У меня довольно сложная иерархия компонентов и элементов QML. В двух словах:

Существует родительский тип GameGrid QML, который может делать много разных вещей. То, что он может сделать, зависит от того, в каком состоянии находится GameGrid. Состояние GameGrid может быть изменено различными функциями в зависимости от текущего состояния GameGrid. Всякий раз, когда GameGrid изменяет состояния, он автоматически запускает код, необходимый для обработки всего этого состояния.

Иногда, при изменении состояния, код, который запускается GameGrid должен установить состояние GameGrid на другое значение после завершения обработки.

-

Результат этой операции:

<Неизвестный файл>: QML StateGroup: невозможно применить изменение состояния как часть определения состояния .

Как мне обойти это ограничение или правильно прийти в состояние «play», как только состояние «init» завершит работу?

Я пытался подключение сигналов, функций и назначений.

Единственное, что работает, - это использование отдельного элемента таймера, который впоследствии изменяет состояние. Этот способ слишком сложен, чтобы его реально реализовать в большой кодовой базе, где много состояния и многие изменения этих состояний, иногда асинхронно.

Вот минимальный код для воспроизведения этой ошибки


GameGrid.qml

import QtQuick 2.0

Item {
    id: gameGrid
    states: [
            State {
                name: "init"
                StateChangeScript {
                    script: {
                        console.log("Init actions");
                        gameGrid.state = "play";    /* causes the error */
                    }
                }
            },
        State {
            name: "play"
            StateChangeScript {
                script: {
                    console.log("Play Actions");  /* never does actions */
                }
            }
        }
        ]

    Text {
        anchors.centerIn: parent
        text: parent.state
    }

}

main.qml

import QtQuick 2.12
import QtQuick.Window 2.12

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")
    GameGrid {
        id: grid
        anchors.fill: parent
    }
    Component.onCompleted:  {
        grid.state = "init";
    }
}

main. cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>

int main(int argc, char *argv[])
{
  QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

  QGuiApplication app(argc, argv);

  QQmlApplicationEngine engine;
  const QUrl url(QStringLiteral("qrc:/main.qml"));
  QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                   &app, [url](QObject *obj, const QUrl &objUrl) {
    if (!obj && url == objUrl)
      QCoreApplication::exit(-1);
  }, Qt::QueuedConnection);
  engine.load(url);

  return app.exec();
}

StateTest.pro

QT += quick

CONFIG += c++11

DEFINES += QT_DEPRECATED_WARNINGS



SOURCES += \
        main.cpp

RESOURCES += qml.qrc


QML_IMPORT_PATH =


QML_DESIGNER_IMPORT_PATH =


qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

1 Ответ

1 голос
/ 26 января 2020

Определение переходов в GameGrid для изменения состояния конечного автомата.

Item {
    id: gameGrid

    states: [
            State {
                name: "init"
                StateChangeScript {
                    script: {
                        console.log("Init actions");
                        gameGrid.state = "play";    /* causes the error */
                    }
                }
            },
        State {
            name: "play"
            StateChangeScript {
                script: {
                    console.log("Play Actions");  /* never does actions */
                }
            }
        }
    ]

    transitions: Transition { }
}
...