首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >QJSEngine -公开类和抛出错误

QJSEngine -公开类和抛出错误
EN

Stack Overflow用户
提问于 2020-04-27 00:59:17
回答 1查看 545关注 0票数 3

我正在尝试创建一个标准的JS库,它的形状大多类似于Qt (它使用的是废弃的QScriptEngine)和QJSEngine,这样,制作Qt软件的人就可以将文件操作之类的东西添加到他们的插件JS环境中。

你可以看到回购这里

我已经将基本类暴露在JS引擎中,如下所示:

代码语言:javascript
复制
QJSEngine jsEngine;
jsEngine.installExtensions(QJSEngine::AllExtensions);

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

但是,我似乎知道如何在函数中获得对QJSEngine的引用,这样我就可以抛出一个错误:

代码语言:javascript
复制
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()方法,但不知道如何使用它。

我加了

代码语言:javascript
复制
Depends { name: "Qt.script" }

在我的qbs文件中

代码语言:javascript
复制
#include <QtScript>

但是它仍然没有抛出这个错误(只是默默地失败了):

代码语言:javascript
复制
#include <QObject>
#include <QString>
#include <QFile>
#include <QIODevice>
#include <QFileInfo>
#include <QtScript>

namespace Qbs4QJS {

class BinaryFile :  public QObject, protected QScriptable
{
    Q_OBJECT

public:
    Q_ENUM(QIODevice::OpenModeFlag)

    Q_INVOKABLE BinaryFile(const QString &filePath, QIODevice::OpenModeFlag mode = QIODevice::ReadOnly) {
        m_file = new QFile(filePath);
        // should check for false and throw error with jsEngine->throwError(m_file->errorString());
        if (!m_file->open(mode)){
            context()->throwError(m_file->errorString());
        }
    }

private:
    QFile *m_file = nullptr;
};

} // end namespace Qbs4QJS

我也可能对此感到困惑,但它似乎是在使用QScriptEngine,我正试图摆脱它。

完成添加QJSEngine可以使用的类的任务的最佳方法是什么,该类具有cpp定义的方法,可以在调用引擎中抛出错误?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2020-04-29 18:55:43

正在构建的对象还没有与QJSEngine有任何关联。因此,您只能执行下列选项之一:

  1. 如果可以确保整个应用程序中只有一个QJSEngine实例,则将引擎实例存储在静态变量中。
  2. 如果可以确保每个线程只有一个引擎,则将引擎实例存储在线程局部变量(QThreadStorage)中。
  3. 在计算JS代码之前,请在当前线程中设置当前活动引擎。这可能是最简单而又健壮的解决方案。
  4. QJSValue参数中检索引擎。
  5. 为构造函数实现JS包装器

解决方案4.:通过QJSValue参数隐式传递引擎。

我假设抛出构造函数总是有一个参数。QJSValue有一个(不推荐的)方法发动机(),然后您可以使用它。您可以将Q_INVOKABLE方法中的任何参数替换为QJSValue,而不是使用QString和朋友。

代码语言:javascript
复制
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上,甚至对无参数的构造函数也有效。而不是像下面这样直接注册助手类:

代码语言:javascript
复制
    engine->globalObject().setProperty("TextFile", engine->newQMetaObject(&TextFile::staticMetaObject));

您可以在JS中编写额外的生成器类和构造函数包装器。计算包装器,并将此函数注册为类的构造函数。这个包装函数将把所有想要的参数传递给工厂方法。就像这样:

代码语言:javascript
复制
engine->evaluate("function TextFile(path) { return TextFileCreator.createObject(path);

TextFileCreator是一个助手类,您可以将其注册为单例。然后,createObject()方法将最终创建TextFile对象,并将引擎作为paremter传递:

代码语言:javascript
复制
QJSValue TextFileCreator::createObject(const QString &path)
{
    QJSEngine *engine = qmlEngine(this);
    return engine->createQObject(new TextFile(engine, filePath));
}

这使您可以访问TextFile构造函数中的TextFile,并且可以调用throwError()。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61450160

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档