Как выполнить слот QML из C ++ без сигнала? - PullRequest
0 голосов
/ 13 июля 2020

Я получил объект QML в форме QObject. С помощью ->setProperty(..., ...) я могу изменять свойства, но как я могу выполнять слоты без сигналов?

В настоящее время я объявляю сигнал в своем классе C ++:

signals:
  void testSignal();

и сигнал / слот в объекте QML :

signal executeTestFunc(); onExecuteTestFunc: {
  testAnimation.start();
}

Потом соединяю эти два:

QObject::connect(this, SIGNAL(testSignal()),
                 QmlObject, SIGNAL(executeTestFunc()));

Но это не чисто, как я вижу:

  1. Де-факто это странно Соединение СИГНАЛ / СИГНАЛ.
  2. Я не хочу использовать механизм СИГНАЛ / СЛОТ, кроме случаев, когда это необходимо, из-за производительности и длинного кода.

Есть ли способ выполнить QML onExecuteTestFunc(); из QObject напрямую?

Ответы [ 2 ]

3 голосов
/ 13 июля 2020

Вы можете создать класс C ++, который будет излучать сигнал. Этот сигнал будет пойман в QML. Никакого явного connection с SIGNAL / SLOT не требуется. Пример:

C ++:

class Presenter : public QObject
{
    Q_OBJECT
public:
    explicit Presenter()
    {
        QTimer *timer = new QTimer();
        timer->setInterval(500);
        connect(timer, &QTimer::timeout,
                this, &Presenter::timeout);
        timer->start();
    }

    Q_SIGNAL void timeout();
};

QML:

Window {
    ...
    Presenter {
        onTimeout: {
            console.log("called from c++")
        }
    }
}

Результат:

qml: called from c++
qml: called from c++
qml: called from c++
qml: called from c++
...
2 голосов
/ 14 июля 2020

@ Thomenson уже дал хороший ответ о том, как вы можете подключиться к сигналу из C ++ и действовать в соответствии с ним в QML. Его решение работает, если вы можете создать C ++ из QML, что может быть не всегда.

Элемент Connections

Есть два других варианта, которые вы можете рассмотреть. Во-первых, если у вас есть объект, который не был создан из QML, но был помещен в него другим способом (контекст QML, объект stati c, возвращенный из вызываемого объекта ...), вы можете использовать элемент Connections:

Connections {
    target: theObjectWithTheSignal
    onSignalName: {doSomething();}
}

Это гибкий способ реагировать на сигналы от объекта, который вы не создали в QML, или даже на объекты, которые были созданы в другом месте QML.

Обратный вызов с использованием JSValue

Если вы действительно настаиваете на том, чтобы избегать сигнала / слота (хотя я не понимаю почему; Qt и QML построены вокруг него и пытаются избежать этого, он борется с фреймворком вместо использования его сильных сторон), есть другой способ. Вы можете создать свойство типа QJSValue в объекте C ++, который предоставляется QML. Затем, в C ++ при настройке, проверьте, что все, что было установлено, можно вызвать (используя QJSValue::isCallable()). Затем в качестве точки, в которой вы sh запускаете все, что вы хотите выполнить в своем QML, назовите это, используя QJSValue::call.

На стороне QML вы можете просто назначить или привязать что-то вызываемое, как и вы 'd do for a signal handler.

Anti-pattern: QMetaObject :: invokeMethod

Есть еще один способ, который я буду включать только как предупреждение против анти- шаблон. Вы можете вызывать QML из C ++, используя механизм самоанализа Qt. Вы можете найти объект по его значению objectName и вызвать для него любой (вызываемый) метод с помощью QMetaObject :: invokeMethod, прочитать и записать любое свойство и прослушать все сигналы. Сюда входят методы вызова, которые вы определили в QML. Используя это, вы можете управлять своим QML из вашего C ++. Не делай этого. Это приводит к негибкому и неподдерживаемому коду.

...