QJSEngine - разоблачение классов и выбрасывание ошибок - PullRequest
2 голосов
/ 27 апреля 2020

Я пытаюсь создать стандартную библиотеку JS, которая в основном имеет форму, подобную Qbs (которая использует устаревший QScriptEngine) с QJSEngine, поэтому люди, которые делают программное обеспечение Qt, могут добавлять такие вещи, как файловые операции, в свой плагин JS environment.

Вы можете увидеть репо здесь

У меня есть базовые c классы, открытые для движка JS, например:

QJSEngine jsEngine;
jsEngine.installExtensions(QJSEngine::AllExtensions);

jsEngine.globalObject().setProperty("BinaryFile", jsEngine.newQMetaObject(&Qbs4QJS::BinaryFile::staticMetaObject));

но я, кажется, могу понять, как получить ссылку на QJSEngine внутри функции, чтобы я мог выдать ошибку:

Q_INVOKABLE BinaryFile(const QString &filePath, QIODevice::OpenModeFlag mode = QIODevice::ReadOnly) {
    m_file = new QFile(filePath);
    if (!m_file->open(mode)) {
        // how do I get jsEngine, here
        jsEngine->throwError(m_file->errorString());
    }
}

Мне бы хотелось если бы я мог каким-то образом получить вызывающий механизм изнутри функции, чтобы класс мог быть представлен, например, нескольким отдельным экземплярам механизма.

Я видел QScriptable и это метод engine(), но не могу понять, как его использовать.

Я добавил

Depends { name: "Qt.script" }

в свой файл qbs и

#include <QtScript>

, но он все еще не выбрасывает ошибка с этим (просто молча) Он использует QScriptEngine, от которого я пытаюсь избавиться.

Каков наилучший способ выполнить sh задачу добавления класса, который может использовать QJSEngine, с cpp -определенные методы, которые могут генерировать ошибки в вызывающем движке?

1 Ответ

2 голосов
/ 29 апреля 2020

Строящийся объект еще не связан с QJSEngine. Таким образом, вы можете сделать только одну из следующих альтернатив:

  1. Сохраните экземпляр движка в переменной stati c, если вы можете быть уверены, что во всем приложении есть только один экземпляр QJSEngine .
  2. Сохраните экземпляр механизма в локальной переменной потока (QThreadStorage), если вы можете гарантировать, что в каждом потоке есть только один механизм.
  3. Установить текущий активный механизм в текущем потоке прямо перед оценкой вашего JS кода с тех пор. Возможно, это самое простое и надежное решение.
  4. Извлечение механизма из параметра QJSValue.
  5. Реализация оболочки JS для конструктора

Решение 4 .: Неявная передача двигателя через параметр QJSValue.

Я предполагаю, что у вашего конструктора броска всегда есть параметр. QJSValue имеет (устаревший) метод engine () , который вы затем можете использовать. Вы можете заменить любой параметр в методе Q_INVOKABLE на QJSValue вместо использования QString и друзей.

class TextFileJsExtension : public QObject
{
    Q_OBJECT
public:
    Q_INVOKABLE TextFileJsExtension(const QJSValue &filename);
};

TextFileJsExtension::TextFileJsExtension(const QJSValue &filename)
{
    QJSEngine *engine = filename.engine();
    if (engine)
        engine->throwError(QLatin1String("blabla"));
}

Я думаю, есть причина, по которой он устарел, поэтому вы можете задать QML команда, почему и какую альтернативу вы можете использовать.

Решение 5 Реализация оболочки JS для конструктора

Это основывается на решении 4. и работает даже для параметра без конструкторов. Вместо прямой регистрации вашего вспомогательного класса, например, так:

    engine->globalObject().setProperty("TextFile", engine->newQMetaObject(&TextFile::staticMetaObject));

Вы можете написать дополнительный класс генератора и оболочку конструктора в JS. Оцените оболочку и зарегистрируйте эту функцию в качестве конструктора для вашего класса. Эта функция-обертка передает все нужные аргументы фабричному методу. Примерно так:

engine->evaluate("function TextFile(path) { return TextFileCreator.createObject(path);

TextFileCreator - это вспомогательный класс, который вы бы зарегистрировали как singleton. Затем метод createObject() в конце концов создаст объект TextFile и передаст обработчик как паромер:

QJSValue TextFileCreator::createObject(const QString &path)
{
    QJSEngine *engine = qmlEngine(this);
    return engine->createQObject(new TextFile(engine, filePath));
}

Это даст вам доступ к QJSEngine в конструкторе TextFile и вы можете вызвать throwError () .

...