これは何が起こったのかを示す小さなデモです。
仕組み
このプラグインのアイデアは非常に単純です-初期化中、
bool initialize(const QStringList &arguments, QString *errorString)
関数
bool initialize(const QStringList &arguments, QString *errorString)
で、プラグインフォルダー内の特別な「スクリプト」プラグインを探します。 これらは* .gala拡張子を持つJavaScriptファイルであり、次の構成要素が含まれる場合があります。
- 必須の関数
initialize()
は、スクリプトをロードした直後に呼び出されます。 - オプションの
extensionsInitialized()
関数。メインプラグインの対応する関数で呼び出されます(すべてのプラグインがロードされた場合)。 - オプションの
aboutToShutdown()
関数。QtCreatorを閉じる前に呼び出されます。 - オプションの整数変数
galaPluginOrder
。起動時にスクリプトプラグインの順序を変更するために使用されます。 - オプションのブール変数
galaPluginDisable
を使用すると、スクリプトプラグインを無視できます。 - オプションのブール変数
galaPluginTrace
。これにより、すべてのgalaPluginTrace
呼び出しをログに記録できます(デバッグに役立ちます)。
モードバーに[すべて保存]ボタンを追加するSaveAllBttn.galaスクリプトプラグインの例を次に示します
SaveAllBttn.gala
var galaPluginOrder = 1; var galaPluginTrace = true; function saveAllAction() { var docs = editorManager.documents(); for (var i = 0; i < docs.length; ++i) { var doc = docs[i]; if (doc.isModified()) { doc.save("", false); } } } function createSaveAllButton() { var bttn = galaAPI.createQObject("QPushButton", modeManager); bttn.flat = true; bttn.text = "Save All"; bttn.focusPolicy = 0; bttn.styleSheet = "QPushButton {color: white; }"; // disable button minimum width bttn.sizePolicy = galaAPI.sizePolicy(13, 0, 1); bttn.clicked.connect(saveAllAction); return bttn; } function initialize() { modeManager.addWidget(createSaveAllButton()); galaAPI.debug("Success initialize"); } function extensionsInitialized() { galaAPI.debug("Success extensionsInitialized"); } function aboutToShutdown() { galaAPI.debug("Success aboutToShutdown"); }
さらに、さらに4つのスクリプトプラグインを使用できます。
- CloseAllBttn-すべてのドキュメントの閉じるボタンをモードバーに追加します
- CloseAllToolMenu-メニュー項目[ツール]-> [マイプラグイン]-> [すべて閉じる]を追加します
- 時計-アニメーション化されたデジタル時計をモードバーに追加します
- RelaxTracker-特別なQMLオブジェクトを追加します。このオブジェクトは、一定の間隔で、緑色の長方形を赤色に変更し、点滅する碑文「Break」(元の記事のアイデア)を付けます。
- 天気-簡単な天気情報をモードバーに追加します
スクリプトからQtCreator APIを使用するために、必要なクラス(
Core::ICore
、
Core::Command
、
Core::ActionManager
など)のラッパーを作成しました。 ラッパーを作成するプロセスはほとんど機械的です。QObjectの下位クラスを作成し、QtCreator APIからクラスへのポインターを渡し、保存し、パブリックスロットセクションでラッパーのソースクラスのすべてのパブリックメソッドを呼び出します。
以下に小さな例を示します。
class GModeManager : public GWrapper { Q_OBJECT public: GModeManager(QJSEngine* jsEngine) : GWrapper(jsEngine), m_owner(qobject_cast<Core::ModeManager*>(Core::ModeManager::instance())) { Q_ASSERT(m_owner); } ~GModeManager() {} Core::ModeManager* owner1() { return m_owner; } public slots: QJSValue owner() { return m_jsEngine->toScriptValue(m_owner); } QJSValue currentMode() { return m_jsEngine->toScriptValue(m_owner->currentMode()); } QJSValue mode(QString id) { return m_jsEngine->toScriptValue(m_owner->mode(str2id(id))); } void addAction(QAction *action, int priority) { m_owner->addAction(action, priority); } void addProjectSelector(QAction *action) { m_owner->addProjectSelector(action); } void addWidget(QWidget *widget) { m_owner->addWidget(widget); } void activateMode(QString id) { m_owner->activateMode(str2id(id)); } void setFocusToCurrentMode() { m_owner->setFocusToCurrentMode(); } bool isModeSelectorVisible() { return m_owner->isModeSelectorVisible(); } void setModeSelectorVisible(bool visible) { m_owner->setModeSelectorVisible(visible); } private: Core::ModeManager* m_owner; };
オブジェクトへのポインタのリストを返す関数は少し複雑です。JavaScript配列値にパックする必要があります。
editorManager.documents()
関数の実装例は次の
editorManager.documents()
です。
QJSValue documents() { QList<Core::IDocument *> documents = m_owner->documentModel()->openedDocuments(); QJSValue array = m_jsEngine->newArray(documents.size()); for (quint32 i = 0; i < (quint32)documents.size(); ++i) { array.setProperty(i, m_jsEngine->newQObject(new GDocument(m_jsEngine, documents[i]))); } return array; }
現在、JavaScript / QML環境では、次のグローバルオブジェクトを使用できます。
- core -
Core::ICore::instance()
表しCore::ICore::instance()
- messageManager -
Core::MessageManager::instance()
表しCore::MessageManager::instance()
- actionManager -
Core::ActionManager::instance()
表しCore::ActionManager::instance()
- editorManager -
Core::EditorManager:instance()
導入しCore::EditorManager:instance()
- modeManager-
Core::ModeManager::instance()
表しCore::ModeManager::instance()
- galaAPI-補助的な便利な機能へのアクセスポイントとして機能
プラグインの作成中に、次の問題が発生しました。
スロットがQObject継承オブジェクトへのポインターを返す場合、JavaScript環境はこのオブジェクトの所有権を取得します。 これは、スロットがラッパーを作成してJSコードに返す場合に便利です。 例えば
GCommand *command(QString id) { return new GCommand(m_jsEngine, m_owner->command(str2id(id))); }
スロットが内部QtCreatorオブジェクトを返す場合、環境はそれを所有してはなりません。 このような場合、オブジェクトへのポインターではなく、ポインターをラップするQJSValueを返す必要があります。
// QMenu* QJSValue menu() const { return m_jsEngine->toScriptValue(static_cast<QObject*>(m_owner->menu())); }
JSでのシグナル転送に関する別の問題は、デフォルトのパラメーターと同じメソッド名です。
メソッド
foo
がJSから呼び出されると、その名前のメソッドがオブジェクトのメタシステムで検索され、最初のメソッドが呼び出されます。 パラメーターの数(特にタイプ)の比較はありません。 この場合、信号にデフォルトのパラメーターがある場合、mocはいくつかのメタメソッドを生成します。 たとえば、シグナル
void foo(int a, int b = 0, int c = 1);
3つのメタメソッドが生成されます
void foo(int a); void foo(int a, int b); void foo(int a, int b, int c);
そして、この順序で-最初の最短バージョンです。 したがって、JSでデフォルトのパラメーターを使用することはできず、すべてのパラメーターを手動で渡す必要があります。 そして、同じ名前のメソッドを一意にします。
おわりに
このプラグインを使用すると、QtCreator'aの機能を非常に簡単に拡張できます。 モードパネルで視覚要素を作成し、頻繁に使用するコマンドや特定のコマンドのツールバーとメニュー項目を作成する際に、スクリプトプラグインの主な使用法を見ています。 QMLオブジェクトを埋め込む機能は、素晴らしい機会を提供します。 天気、為替レート、お気に入りのリソースに関する新しい記事、スポーツのアカウント、ビルドステータスなど、あらゆるWebサービスを監視するQMLビューを簡単に作成できます。 私はQMLの専門家ではありませんが、ネット上には多くの興味深い例があります。
面白いアイデアをお持ちの場合、またはさらに良いことに、興味深いスクリプトプラグインを実装している場合は、コミュニティで共有してください。 私は自分のプロジェクトにそれを追加させていただきます。
また、さまざまなプラットフォーム用にプラグインをコンパイルする際に助けを求めます。 Windowsの場合、問題はLinuxの場合と同様に簡単に構築できます。 MacOSでは、ビルドする方法はまったくありません。
PS最後まで読んだ人のためのPS、別のビデオ: