3

私は Qt から始めており、私のプロジェクトの 1 つは QJSEngine を使用して JavaScript を評価しており、クラスとグローバル関数を使用してスクリプトに API 全体を提供したいと考えています。

現在、私のプログラムは ECMAScript のデフォルトのもの (eval、encodeURI、parseInt など) のみを提供していますが、ブラウザー API (WebSocket クラス、Image クラス、ドキュメント オブジェクト) など、いくつかのカスタム クラスをコードに公開する必要があります。例えば:

var obj = new CustomClass("", 0);
var ret = obj.customClassMethod("[...]!");
customFunction(ret);

C++ でクラスの動作を定義する必要がありますが、クラス定義を評価してユーザー コードを実行させるのには役立ちません。

4

4 に答える 4

9

マクロを使用してQScriptEngineから継承する場合にカスタム クラスを追加できるとは対照的に、はこの機能を直接提供しません。QObjectQ_SCRIPT_DECLARE_QMETAOBJECTQJSEngine

Qt メタオブジェクト システムを使用して Javascript のインターフェイスを提供することはできますが、オブジェクトを C++ でインスタンス化し、それを Javascript コンテキストに追加する必要があります。次に、そのスロット、 で定義されたメソッドQ_INVOKABLE、および で定義されたプロパティQ_PROPERTYはすべて、Javascript ランタイム内からアクセスできます。

これで、Javascript オブジェクトとしてラップされCustomClassた特定のカスタム クラスのインスタンスを作成するファクトリを作成できます。QJSEngine

class CustomClassFactory : public QObject
{
    Q_OBJECT
public:
  CustomClassFactory(QJSEngine* engine) : m_engine(engine) {}
  Q_INVOKABLE QJSValue createInstance() {
      // The engine takes ownership and destroys the object if no longer required.
      return m_engine->newQObject(new CustomClass());
  }
private:
    QJSEngine* m_engine;
}

ファクトリ インスタンスを構築し、Javascript ランタイムのグローバル オブジェクトに追加する必要があります。

QJSEngine engine;
QJSValue factoryObj = engine.newQObject(new CustomClassFactory());
engine.globalObject().setProperty("_customClassFactory", factoryObj);

これで、Javascript でオブジェクトを構築できるようになりました。

var obj = _customClassFactory.createInstance()

ここまで来たので、カスタム クラスのコンストラクターを Javascript ランタイムにさらに挿入します。

QJSEngine engine;
// Again, the QJSEngine will take ownership of the created object.
QJSValue factoryObj = engine.newQObject(new CustomClassFactory());
engine.globalObject().setProperty("_customClassFactory", factoryObj);
engine.evaluate(
    "function CustomClass() {"
    "    return _customClassFactory.createInstance()"
    "}");

ほら、カスタム Javascript クラスのように、Javascript で C++ オブジェクトを構築できるようになりました。

var obj = new CustomClass()

前述のWebSocketAPI については、その目的のためにラップすることができますQtWebSocket。提案されたアプローチを思いついたとき、まさにそれが必要でした。

簡単にするために、コンストラクターのパラメーターを省略しましたが、単純に追加することもできます。

PS: 公式ドキュメントへのリンクをもっと追加したかったのですが、評判が悪いため許可されていません。

于 2016-06-01T18:11:21.420 に答える
3

Qt 5.8 では、QJSEngine に新しい機能が追加されました。newQMetaObject

&MyQObjectDerivedClass::staticMetaObject上記の関数を使用して、たとえば JSEngine に静的メタ オブジェクトを追加するだけです。

newその後、QML 内から Javascript でこれらのオブジェクトにアクセスできるようになります。私はこれが非常にきちんとした解決策であることを発見しました。

ドキュメントにあるように、コンストラクターをマークする必要Q_INVOKABLEがあります。そうしないと、クラスのオブジェクトをインスタンス化できません。

プロパティ システム (セッター/ゲッター) は、スロットと同様に期待どおりに機能します。

https://doc.qt.io/qt-5/qjsengine.html#newQMetaObject

これが私のテスト コードです。最初は、メタ オブジェクトを追加する C++ の部分です。

QQmlApplicationEngine engine;
QJSValue jsMetaObject = engine.newQMetaObject(&MyClassOfObject::staticMetaObject);
engine.globalObject().setProperty("MyClassOfObject", jsMetaObject);

そのタイプのオブジェクトであるJS を作成しnews、セッター/ゲッターなどを使用できるようになりました。このコードは、手動テスト用に MouseArea onClicked ハンドラーに実際に存在します。

var bob = new MyClassOfObject();
print(bob.x);
bob.x = 918264;
print(bob.x);
print(bob.words);

そして、ここにクラス定義があります...

class MyClassOfObject : public QObject
{
    Q_OBJECT
    Q_PROPERTY(int x READ getX WRITE setX)
    Q_PROPERTY(int y READ getY WRITE setX)
    Q_PROPERTY(QStringList words READ getWords)    
public:
    Q_INVOKABLE explicit MyClassOfObject(QObject *parent = nullptr);
public slots:
    int getX() const { return x; }
    int getY() const { return y; }
    void setX(int x) { this->x = x; }
    void setY(int y) { this->y = y; }
    QStringList getWords() const;
private:
    int x = -113;
    int y = 616;
    QStringList stringList;
};
于 2020-05-07T14:09:56.590 に答える
-1

QScriptEngine のドキュメントを参照するか、「QScriptEngine の例」を検索すると、カスタム C++ クラスを QScriptEngine で使用できるようにする方法についての情報が見つかります。

ここから始めるのが良いでしょう: 例へのリンク

QScriptEngine は QJsEngine に非常に似ているため、大きな問題にはなりません。

お役に立てれば :)

于 2013-11-01T05:15:56.757 に答える