2020年11月3日 星期二

用 JavaScript 裡綁定類別

用 JavaScript 裡綁定類別

前言

  在之前的 用 JavaScript 控制 Widget  裡使用了 Qt 的 Widget 在 JavaScript 中,如果要在 JavaScript 裡使用自己設計的類別有可能嗎?答案是可以的,要如何做呢?在此把學習的過程作紀錄。


內容

  先到 [ GitLab ] HelloQt 下載範例,這次應用的專案路徑
(HelloQt' directory)/JSEngine/WrapClass,執行結果如下

範例的執行結果



範例的上方會有預設的程式碼,按下右下的"Run"可以執行,執行預設的程式碼看列印的偵錯訊息。


  要在 JavaScript 綁定自己的類別,該類別必須繼承 QObject ,這很重要!利用 Qt Creator 的精靈產生類別的話,如下圖

使用精靈產生繼承 QObject 的類別

在精靈的"Class name"填上類別名稱,在"Base class"選擇 QObject 後即可,範例已產生"MyClass",所以看到"MyClass"的宣告,如下

#include <QObject>

class MyClass : public QObject
{
  Q_OBJECT
  Q_PROPERTY(int dataInt READ myInt WRITE setMyInt)
  Q_PROPERTY(double dataDouble READ myDouble WRITE setMyDouble)
  Q_PROPERTY(QString dataString READ myString WRITE setMyString)
public:
  explicit MyClass(QObject *parent = nullptr);
//
  void setMyInt( int value );
  int myInt() const;
  void setMyDouble( double value );
  double myDouble() const;
  void setMyString( const QString& value );
  QString myString() const;
  Q_INVOKABLE void callMethod();
signals:
private:
  int m_MyInt;
  double m_MyDouble;
  QString m_MyString;
};


MyClass 會綁定三個 Property ,"m_MyInt"、"m_MyDouble"與"m_MyString",並綁定一個 Function 名為"callMethod",綁定 Function 到 JavaScript 的部分比較簡單,只需再開頭加"Q_INVOKABLE"即可,但要注意輸入的引數與回傳值得資料型態必須是 JavaScript 可以接受的型態,至於那些型態可以接受以後來研究,這次都先使用基本的型態。在綁定 Property 的部份就比較麻煩一些,綁定些要用到"Q_PROPERTY"來綁定,後方的內容要照一定的格式寫,就拿 m_MyInt 來說,"int"是綁定到 JavaScript 的型態,這個型態最後會被自動轉成 JavaScript 的 "Number" ,"dataInt" 是 Property 的名稱,可以自己命名,不一定要和 C++ 這邊的變數同名,"READ myInt"指的是讀取時所喚起的 Function ,在這裡會喚起 myInt() ,接著是"WRITE setMyInt"指的是寫的時候所喚起的 Function ,這裡會喚起 setMyInt() 。在讀與寫的 Function 也要注意資料型態的問題,字串的部份要用 QString 來綁定而非 std::string, MyClass 的實作部分沒什麼好說明就直接略過,接著看到 MainWindow::MainWindow() ,如下

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
  ui->setupUi(this);
  //
  connect( ui->runButton , &QPushButton::clicked , this , &MainWindow::onRunButtonClicked );
  //
  m_cJSEngine.installExtensions( QJSEngine::ConsoleExtension );
  //
  MyClass* pMyClass = new MyClass();
  m_cJSEngine.globalObject().setProperty( "myClass" ,m_cJSEngine.newQObject( pMyClass ) );
  //
  ui->textEdit->setText( tr(
    "console.log( myClass.dataInt );\n"\
    "console.log( myClass.dataDouble );\n"\
    "console.log( myClass.dataString );\n"\
    "myClass.dataInt = 5678;\n"\
    "myClass.dataDouble = 1.414;\n"\
    "myClass.dataString = 'My string';\n"\
    "console.log( myClass.dataInt );\n"\
    "console.log( myClass.dataDouble );\n"\
    "console.log( myClass.dataString );\n"\
    "myClass.callMethod();\n"\
  ) );
}


程式開頭依舊初始化與綁定事件,這次就不說明了,接著直接 New 一個 MyClass ,透過  QJSEngine::newQObject() 來新增變數,就像上次在 用 JavaScript 控制 Widget  裡做的一樣,就著就是寫下預設的 JavaScript 程式碼,單純列印變數與喚起 Method ,這就不說明了。


參考資料

[ doc.qt.io ] QJSEngine Class


相關文章與資料

[ GitLab ] HelloQt

用 JavaScript 控制 Widget

沒有留言:

張貼留言