JavaScript からの動的な QML オブジェクトの作成
QML は、JavaScript 内からのオブジェクトの動的生成をサポートしています。これは、オブジェクトのインスタンス化を必要な時まで遅らせることで、アプリケーションの起動時間を短縮するのに役立ちます。また、ユーザーの入力やその他のイベントに応じて、ビジュアルオブジェクトを動的に生成し、シーンに追加することも可能です。
警告: 信頼できないソースからオブジェクトを 動的に生成してはなりません。静的なQMLソースに対する制限は、動的なオブジェクト生成にも同様に適用されます。
オブジェクトの動的生成
JavaScriptからオブジェクトを動的に生成するには2つの方法があります。Qt.createComponent()を呼び出してComponent オブジェクトを動的に生成するか、Qt.createQmlObject()を使用してQML文字列からオブジェクトを生成することができます。QMLドキュメントに既存のコンポーネントが定義されており、そのコンポーネントのインスタンスを動的に生成したい場合は、コンポーネントを生成する方が適しています。 それ以外の場合は、オブジェクトのQML自体が実行時に生成される場合に、QML文字列からオブジェクトを作成するのが便利です。
コンポーネントの動的な作成
QML ファイルで定義されたコンポーネントを動的に読み込むには、Qt object のQt.createComponent() 関数を呼び出します。この関数は、QML ファイルの URL を唯一の引数として受け取り、この URL からComponent オブジェクトを作成します。
Component を入手したら、そのcreateObject() メソッドを呼び出して、コンポーネントのインスタンスを作成できます。この関数には、1つまたは2つの引数を指定できます。
- 1つ目は、新しいオブジェクトの親です。親は、グラフィカルオブジェクト(つまり、Item 型)でも、非グラフィカルオブジェクト(つまり、QtObject 型またはC++のQObject 型)でも構いません。グラフィカルな親オブジェクトを持つグラフィカルオブジェクトのみが、 Qt Quick 。後で親を設定したい場合は、この関数に
nullを安全に渡しすることができます。 - 2つ目はオプションであり、オブジェクトの初期プロパティ値を定義するプロパティと値のペアのマップです。この引数で指定されたプロパティ値は、オブジェクトの作成が完了する前に適用されるため、他のプロパティのバインディングを有効にするために特定のプロパティを初期化しなければならない場合に発生しうるバインディングエラーを回避できます。 さらに、オブジェクトの作成後にプロパティ値やバインディングを定義する場合と比較して、わずかながらパフォーマンス上のメリットがあります。
以下に例を示します。まず、Sprite.qml には、単純な QML コンポーネントが定義されています。
import QtQuick
Rectangle { width: 80; height: 50; color: "red" }メインのアプリケーションファイルである `main.qml` は、`Sprite ` オブジェクトを作成する JavaScript ファイル `componentCreation.js ` をインポートしています:
import QtQuick
import "componentCreation.js" as MyScript
Rectangle {
id: appWindow
width: 300; height: 300
Component.onCompleted: MyScript.createSpriteObjects();
}以下が `componentCreation.js` です。QMLファイルがネットワーク経由で読み込まれ、すぐに利用できない場合を想定して、`status ` コンポーネントが `Component.Ready ` であるかどうかを確認してから、`createObject()` を呼び出している点に注目してください。
var component;
var sprite;
function createSpriteObjects() {
component = Qt.createComponent("Sprite.qml");
if (component.status == Component.Ready)
finishCreation();
else
component.statusChanged.connect(finishCreation);
}
function finishCreation() {
if (component.status == Component.Ready) {
sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
console.log("Error creating object");
}
} else if (component.status == Component.Error) {
// Error Handling
console.log("Error loading component:", component.errorString());
}
}読み込むQMLファイルがローカルファイルであることが確実な場合は、finishCreation() 関数を省略し、createObject()を直ちに呼び出すことができます:
function createSpriteObjects() {
component = Qt.createComponent("Sprite.qml");
sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
console.log("Error creating object");
}
}どちらの場合も、動的に作成されるオブジェクトはビジュアル(Qt Quick )オブジェクトであるため、createObject() の呼び出し時にはappWindow を親引数として渡すことに注意してください。作成されたオブジェクトは、main.qml 内のappWindow オブジェクトの子となり、シーンに表示されます。
相対パスでファイルを使用する場合、そのパスはQt.createComponent() が実行されるファイルを基準とする必要があります。
動的に作成されたオブジェクトにシグナルを接続(またはシグナルを受信)するには、connect() メソッドを使用します。詳細については、「メソッドおよびシグナルへのシグナルの接続」を参照してください。
また、incubateObject() 関数を使用することで、ブロックすることなくコンポーネントをインスタンス化することも可能です。
QML文字列からオブジェクトを作成する
警告: QML の文字列からオブジェクトを作成すると 、そのたびにエンジンが渡された QML 文字列をコンパイルする必要があるため、処理が非常に遅くなります。 さらに、プログラムで QML コードを構築する際、無効な QML コードを生成してしまう可能性が非常に高くなります。文字列操作によって新しいコンポーネントを作成するよりも、QML コンポーネントを個別のファイルとして保持し、プロパティやメソッドを追加してその動作をカスタマイズする方がはるかに望ましいです。
実行時まで QML が定義されていない場合は、次の例のように、Qt.createQmlObject() 関数を使用して QML 文字列から QML オブジェクトを作成できます。
const newObject = Qt.createQmlObject(`
import QtQuick
Rectangle {
color: "red"
width: 20
height: 20
}
`,
parentItem,
"myDynamicSnippet"
);最初の引数は、生成するQMLの文字列です。 新しいファイルの場合と同様に、使用したい型はすべてインポートする必要があります。2番目の引数は新しいオブジェクトの親オブジェクトであり、コンポーネントに適用される親引数の意味論は、createQmlObject()() に対しても同様に適用されます。3番目の引数は、新しいオブジェクトに関連付けるファイルパスであり、これはエラー報告に使用されます。
QML文字列内で相対パスを使用してファイルをインポートする場合、そのパスは親オブジェクト(メソッドの2番目の引数)が定義されているファイルを基準とする必要があります。
重要: 静的 QML アプリケーションをビルドする際 、QML ファイルがスキャンされ、インポートの依存関係が検出されます。これにより、必要なすべてのプラグインとリソースがコンパイル時に解決されます。ただし、明示的なインポート文(QML ファイルの先頭にあるもの)のみが考慮され、文字列リテラル内に含まれるインポート文は考慮されません。 したがって、静的ビルドをサポートするには、Qt.createQmlObject() を使用する QML ファイルにおいて、文字列リテラル内のものに加えて、ファイルの先頭にも必要なすべてのインポートを明示的に記述する必要があります。
動的に作成されたオブジェクトの管理
動的に作成されたオブジェクトを管理する場合、作成コンテキストが作成されたオブジェクトよりも長く存続するようにする必要があります。そうしないと、作成コンテキストが先に破棄された場合、動的オブジェクト内のバインディングやシグナルハンドラが機能しなくなります。
実際の生成コンテキストは、オブジェクトの生成方法によって異なります。
- Qt.createComponent() が使用される場合、生成コンテキストは、このメソッドが呼び出されたQQmlContext となります。
- Qt.createQmlObject()が呼び出された場合、生成コンテキストは、このメソッドに渡された親オブジェクトのコンテキストとなります
Component{}オブジェクトが定義されており、そのオブジェクトに対してcreateObject()またはincubateObject()が呼び出された場合、生成コンテキストはComponentが定義されているコンテキストとなります
また、動的に作成されたオブジェクトは他のオブジェクトと同じように使用できますが、QML では ID を持たない点に注意してください。
オブジェクトの動的な削除
多くのユーザーインターフェースでは、ビジュアルオブジェクトを削除する代わりに、その不透明度を 0 に設定するか、画面の外に移動させるだけで十分です。ただし、動的に作成されたオブジェクトが多数ある場合は、未使用のオブジェクトを削除することで、パフォーマンスが大幅に向上する可能性があります。
なお、QML の便利なオブジェクトファクトリ(Loader やRepeater など)によって動的に作成されたオブジェクトを、手動で削除してはなりません。また、自分で動的に作成していないオブジェクトの削除も避けるべきです。
アイテムは、destroy() メソッドを使用して削除できます。このメソッドには、オブジェクトが破棄されるまでの概算の遅延時間をミリ秒単位で指定するオプション引数(デフォルトは 0)があります。
以下に例を示します。application.qml は、SelfDestroyingRect.qml コンポーネントのインスタンスを5つ作成します。各インスタンスはNumberAnimation を実行し、アニメーションが終了すると、ルートオブジェクトに対してdestroy() を呼び出して自身を破棄します:
application.qml | |
SelfDestroyingRect.qml | |
あるいは、application.qml がobject.destroy() を呼び出すことで、作成されたオブジェクトを破棄することもできたでしょう。
なお、オブジェクト内部でそのオブジェクトに対して `destroy()` を呼び出しても安全です。オブジェクトは `destroy()` が呼び出された瞬間に破棄されるわけではなく、そのスクリプトブロックの終了から次のフレームまでの間にクリーンアップされます(遅延時間を 0 以外で指定した場合を除く)。
また、SelfDestroyingRect インスタンスが次のように静的に作成された場合にも注意してください:
Item {
SelfDestroyingRect {
// ...
}
}この場合、オブジェクトは動的に作成された場合にのみ動的に破棄できるため、エラーが発生します。
Qt.createQmlObject() で作成されたオブジェクトも同様に、destroy() を使用して破棄できます:
const newObject = Qt.createQmlObject(`
import QtQuick
Rectangle {
color: "red"
width: 20
height: 20
}
`,
parentItem,
"myDynamicSnippet"
);
newObject.destroy(1000);© 2026 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.