我正在尝试创建一个标准的JS库,该库的形状大多与Qbs(使用已弃用的QScriptEngine
和QJSEngine
相同,因此制作Qt软件的人可以向其添加文件操作等内容插件JS环境。
您可以看到仓库here
我已经向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>
但是它仍然不会抛出错误(只是默默地失败):
#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定义的方法,该方法可能在调用引擎中引发错误?
答案 0 :(得分:2)
正在构造的对象尚未与QJSEngine
关联。因此,您只能执行以下一种选择:
QJSEngine
个实例,则将引擎实例存储在静态变量中。QThreadStorage
)中。QJSValue
参数中获取引擎。 解决方案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中编写一个附加的生成器类和一个构造函数包装器。评估包装并将该函数注册为您的类的构造函数。该包装函数会将所有所需的参数传递给factory方法。像这样:
engine->evaluate("function TextFile(path) { return TextFileCreator.createObject(path);
TextFileCreator
是一个帮助程序类,您将注册为单例。然后,createObject()
方法将最终创建TextFile
对象,并将引擎作为参数传递给
QJSValue TextFileCreator::createObject(const QString &path)
{
QJSEngine *engine = qmlEngine(this);
return engine->createQObject(new TextFile(engine, filePath));
}
这使您可以访问TextFile
构造函数中的 QJSEngine ,并且可以调用 throwError()。