Доступ к Qt API из JavaScript с помощью QJSEngine

Я использую QJSEngine, чтобы сделать приложение доступным для сценариев. Я бы хотел, чтобы сторона JavaScript могла изменять пользовательский интерфейс. Моя главная проблема сейчас — доступ к Qt API из JavaScript.

Для создания виджетов я добавил оболочку createWidget(), которая использует QUILoader:

// JavaScript
var w = helpers.createWidget("QPushButton");

// C++
QJSValue helpers::createWidget(QString type)
{
    QUILoader ld;
    return engine.newQObject(ld.createWidget(type));
}

Я также зарегистрировал все перечисления из qt_getQtMetaObject(), которые, кажется, заботятся обо всех перечислениях на уровне пространства имен из qnamespace.h. Однако это не похоже на часть общедоступного API.

Я действительно должен делать это вручную или я что-то упустил? Разве нет функции registerAllTheThings(), которая создает глобальный объект Qt, через который доступен Qt API?

Если его нет, то у меня проблемы. Я могу создать QWidget с QUILoader, но я не смог найти способ создания других объектов, таких как QStandardItemModel. Я думал, что все классы Qt уже зарегистрированы через qRegisterMetaType(), но они re not: QMetaType::type("QStandardItemModel") терпит неудачу, возвращая UnknownType. Опять же, я пропустил какой-то вызов функции инициализации, который регистрирует все?


person isanae    schedule 01.10.2016    source источник
comment
Хорошо, ни одна из функций-членов в QStandardItemModel или QStandardItem не помечена как Q_INVOKABLE, поэтому я даже не могу их вызвать. Возможно, я просто переоценил возможности сценариев Qt.   -  person isanae    schedule 01.10.2016
comment
Если вам нужно приложение с поддержкой сценариев, используйте QML вместо QtWidgets. Затем вы можете использовать JS изначально со всем вашим API. Вы можете избежать использования очень небольшого количества кода C++ в ядре. Делать это с помощью QtWidgets совершенно навязчиво. Делать это в QML очень просто. QML компилируется на ходу, поэтому с помощью генерации кода вы можете создавать совершенно новые типы во время выполнения.   -  person dtech    schedule 02.10.2016
comment
@ddriver На самом деле это то, над чем я работал последние 4 часа, но это только для расширений. Основное приложение написано на C++. В настоящее время я пытаюсь загрузить файлы QML во время выполнения, но я пока не уверен, как они будут взаимодействовать с материалом QtWidgets.   -  person isanae    schedule 02.10.2016
comment
Вам придется сделать оооооооооооооооооооооооооооооооооооооооооооооооооойй внешний вид...   -  person dtech    schedule 02.10.2016
comment
@ddriver Я не понимаю. Кажется, у них отличная инфраструктура, которая позволяет очень легко вызывать вещи из javascript, но большая часть API на самом деле не помечена Q_INVOKABLE. Если бы это было так, вы могли бы заскриптовать все. Мне немного грустно.   -  person isanae    schedule 02.10.2016
comment
Ну, эти классы C++ Qt задолго до появления QML, поэтому неудивительно, что они не предназначены для использования в QML. Плюс я уже сказал, что это довольно плохая идея. Если ваше приложение не слишком большое, его будет проще портировать на QML.   -  person dtech    schedule 02.10.2016
comment
@ddriver Весь бэкэнд написан на C++, я только начинаю работать с пользовательским интерфейсом, так что было бы неплохо переключиться сейчас. Я посмотрю на это. Большое спасибо за совет.   -  person isanae    schedule 02.10.2016
comment
Вы можете легко использовать QQmlEngine и по-прежнему использовать виджеты, поскольку QML не зависит от пользовательского интерфейса и работает с любыми классами, производными от QObject. Можно даже создавать деревья виджетов в QML, хотя в настоящее время существует регрессия (работавшая в Qt4), которая заставляет отладочную сборку Qt утверждать при помещении виджета в родительский элемент, не являющийся виджетом, в QML.   -  person Kevin Krammer    schedule 02.10.2016


Ответы (1)


Я бы рекомендовал использовать QQmlEngine вместо QJSEngine.

Является производным от QJSEngine, поэтому он может делать то же самое в том же модуле, поэтому нет дополнительных зависимостей.

Он предоставляет простой способ регистрации типов для создания экземпляров в QML, имеет механизм загрузки плагинов (импорт) и т. д.

Я представил это как часть своего выступления на Qt World Summit 2015: https://www.youtube.com/watch?v=7LsKoVrb8C8

person Kevin Krammer    schedule 02.10.2016
comment
Поиграв с этим несколько часов, я понял, что QML — это гибрид, который требует C++ для определенных задач, таких как модель для TreeView. Это не очень подходит для написания расширений. Я прав? - person isanae; 03.10.2016
comment
В основном все типы, которые не являются частью языка JavaScript, в какой-то момент поддерживаются кодом C++. Даже типы самого JavaScript могут напрямую транслироваться в типы C++, но это скрыто внутри движка. При использовании QML для пользовательских интерфейсов, например. с QtQuick, BB10 Cascades или DeclarativeWidgets, то модели часто реализуются непосредственно на C++. Но можно также создавать базовые типы, которые затем могут быть расширены и/или заполнены на стороне скрипта, например. QtQml.Модель ListModel - person Kevin Krammer; 08.10.2016
comment
@KevinKrammer Я знаю, что это было давно, но можно ли опубликовать код? - person bibi; 05.08.2020
comment
Слайды и демонстрационный код @bibi доступны на сайте kdab.com/development. -resources/kdab-qt-world-summit-2015 Просто прокрутите вниз до записи моего выступления У меня также был дополнительный доклад на Qt World Summit 2019 kdab.com/kdab-qt-world-summit-2019/#qml-scripting - person Kevin Krammer; 06.08.2020