QMLでのローダーの使用

こんにちは この記事では、QMLのローダーなどのコンポーネントについて説明します。



これにより、必要なqml要素をアタッチし、プログラムの状態に応じて異なる要素を使用し、まれにしか使用されないパーツをオンデマンドでダウンロードし、リソースを節約できるコンテナーを作成できます。 ローダーはQMLコンポーネントのコンテナーであり、単独では表示されません。



Qt 5バージョンに含まれるQtQuick 2.0のコンポーネントを検討しています。 以前のバージョンでは、このコンポーネントもありますが、機能はわずかに少なくなります。



ローダーのコンテンツの設定


ローダーのコンテンツとして、qml-ファイルまたはコンポーネントへのパスを設定できます。 これらの方法をより詳細に検討してください。



1. qmlファイルへのパス


パスは、sourceパラメーターを介して指定されます。 これは、ローカルファイルへのパスまたはネットワークからのファイルURLのいずれかです。 パスは、絶対パスと相対パスの両方にすることもできます。



ウィンドウ領域でマウスをクリックして背景を変更する例を考えてみましょう。



main.qml:

import QtQuick 2.0 Item { id: main property int backgroundNumber: 1 width: 360 height: 360 Loader { id: background anchors.fill: parent source: "Background_1.qml" } MouseArea { anchors.fill: parent onClicked: { background.source = (backgroundNumber == 1 ? "Background_2.qml" : "Background_1.qml") backgroundNumber = (backgroundNumber == 1 ? 2 : 1) } } }
      
      





Background_1.qml

 import QtQuick 2.0 Rectangle { color: "black" }
      
      





Background_2 .qml:

 import QtQuick 2.0 Rectangle { color: "yellow" }
      
      







この方法には1つの利点があります。 qmlコンポーネントからオブジェクトを作成する前に、qmlエンジンは最初にそれをコンパイルする必要があります。 ソースをインストールしない場合、必ずしも必要ではなく、デフォルトで作成されないオブジェクトについては、それぞれ何もコンパイルされません。この方法が最適です。



2.コンポーネント


Loaderのスコープでコンポーネントを定義し、sourceComponentプロパティとして指定できます。 コンポーネントを定義するので、プログラムの全期間にわたってそのコンポーネントからオブジェクトを作成したことがない場合でも、qmlエンジンはそれをコンパイルします。これは欠点です。 同時に、コンポーネントは既にコンパイルされているため、オブジェクトを作成するだけで済み、より高速です。 異なるコンポーネント間で状態を頻繁に切り替える必要がある場合は、この方法が適しています。 同時に、コンポーネントファイルをダウンロードする必要はありません。これは、コンポーネントがディスク上のローカルファイルからダウンロードされるのではなく、ネットワークからダウンロードされる場合、別の明白な利点になります。



別の機能は、指定されたqml-fileのコンテキストでコンポーネントが定義されることです。つまり、ファイルの内容も表示され、このファイルからオブジェクトのプロパティと機能にアクセスできます。



main.qml:

 import QtQuick 2.0 Item { id: main property int backgroundNumber: 1 property color backgroundColor1: "black" property color backgroundColor2: "yellow" width: 360 height: 360 Loader { id: background anchors.fill: parent sourceComponent: background_1 } MouseArea { anchors.fill: parent onClicked: { background.sourceComponent = (backgroundNumber == 1 ? background_2 : background_1) backgroundNumber = (backgroundNumber == 1 ? 2 : 1) } } Component { id: background_1 Rectangle { color: main.backgroundColor1 } } Component { id: background_2 Rectangle { color: main.backgroundColor2 } } }
      
      







この例では、親コンポーネント(メイン)とそのプロパティはbackground_1コンポーネントとbackground_2コンポーネントから見ることができます。



3. setSource()


オブジェクトをqmlで記述する場合、バインディングを使用するだけでなく、その初期パラメーターを設定できます。 上記の2つの方法でローダーを使用してコンポーネントをロードする場合、これは実行できません。



QtQuick 2.0(Qt 5.0)はsetSourceメソッドを導入しました。 作成されたオブジェクトのプロパティを設定できます。 これを行うには、関数の2番目の引数として、必要なパラメーターを持つ通常のJavaScriptオブジェクトを渡す必要があります。



例として、不透明度を設定します。 透明度(より正確には、不透明度)。



main.qml:

 import QtQuick 2.0 Item { id: main property int backgroundNumber: 1 width: 360 height: 360 Loader { id: background anchors.fill: parent Component.onCompleted: setSource("Background_1.qml", { "opacity": 0.5 }) } MouseArea { anchors.fill: parent onClicked: { background.setSource(backgroundNumber == 1 ? "Background_2.qml" : "Background_1.qml", { "opacity": 0.5 }) backgroundNumber = (backgroundNumber == 1 ? 2 : 1) } } }
      
      







同期および非同期ロード


デフォルトでは、ディスク上のローカルファイルパスへのソースパスとして設定されているコンポーネントは同期的にロードされます。 ネットワークからファイルURLを指定すると、ステータスはLoader.Loadingに変わり、ダウンロードは非同期になります。



非同期プロパティをtrueに設定することにより、非同期ブートモードを手動でアクティブにすることもできます。



ダウンロードに時間がかかる場合は、ダウンロードの進行状況に関する情報が役立つ場合があります。 progressプロパティは、コンポーネントのロード状態(0〜1)を表示します。



オブジェクトアクセス


作成されたオブジェクトには、itemプロパティを使用してアクセスできます。 したがって、オブジェクトのプロパティにアクセスできます(setSourceを使用してオブジェクトが作成されていない場合、これがオブジェクトの目的のプロパティを設定する唯一の方法です)。



オブジェクトのプロパティを設定するだけでなく、ハンドラーをそのシグナルに添付してメソッドを呼び出すこともできます。 唯一のものは、コンポーネントがロードされるのを待つことです。 statusパラメーターがLoader.Readyと等しくなるまで待機するか、読み込まれたシグナルにハンドラーを配置する必要があります。



小さな例を考えてみましょう。



main.qml:

 import QtQuick 2.0 Item { id: main width: 360 height: 360 Loader { id: background anchors.fill: parent asynchronous: true source: "Background_1.qml" onStatusChanged: console.log("status", status, "item", item) onLoaded: item.color = "green" } }
      
      







出力として得られるものは次のとおりです。

status 2 item null





status 2 item null





status 1 item QQuickRectangle(0x95436f8)







番号2はLoader.Loading、1-Loader.Readyの値に対応します。 オブジェクトのロードが完了したときに、アイテムが作成されたオブジェクトを指していることも確認できます。 ダウンロードが完了すると、背景色が緑色に変わります。



信号を操作する


Loaderにロードされたオブジェクトのシグナルにハンドラーを設定するには、このシグナルでconnect()メソッドを呼び出し、ハンドラー関数をパラメーターとして渡す必要があります。 ハンドラーは、対応するdisconnect()メソッドを使用して削除できます。



例を考えてみましょう。



main.qml:

 import QtQuick 2.0 Item { id: main width: 360 height: 360 Loader { id: container anchors.fill: parent source: "Mouse.qml" onLoaded: item.mouseClicked.connect(processMouse) Component.onDestruction: { if (item) { item.mouseClicked.disconnect(processMouse) } } } function processMouse() { console.log("mouse clicked!") } }
      
      







Mouse.qml:

 import QtQuick 2.0 Item { id: m signal mouseClicked() MouseArea { anchors.fill: parent onClicked: m.mouseClicked() } }
      
      





コンソールのウィンドウをクリックすると、テキストが表示されます:「マウスがクリックされました!」



このメソッドは強力で、プログラムの状態に応じてハンドラーを設定/削除できます。 これに対する代償は、複雑さ、コード量の増加、および信頼性の低下です。 信号を手動で制御する必要がない場合は、Connections qmlコンポーネントを使用できます。 ターゲットプロパティとして、itemを指定し、要素自体で定義したかのようにハンドラーを設定します。



main.qml:

 import QtQuick 2.0 Item { id: main width: 360 height: 360 Loader { id: container anchors.fill: parent source: "Mouse.qml" } Connections { target: container.item onMouseClicked: processMouse() } function processMouse() { console.log("mouse clicked!") } }
      
      







ご覧のとおり、この方法はよりシンプルで便利で、エラーが発生しにくいです。 さらに、このメソッドは宣言型スタイルで作成され、シグナルを対応するハンドラーに手動で接続する場合の命令型とは異なり、qmlの方が自然です。



宣言的アプローチと命令的アプローチについて


上記の例には特に複雑なものはありませんが、非同期にロードするオブジェクトを接続する必要がある場合、それは重要なことです。 特にネットワーク経由でダウンロードされる場合、qmlエンジンが特定のシーケンスでそれらをロードすることを期待しないでください。



経験から、宣言メソッドを使用できる場合は、それらを使用する方が適切です。 これは、信号だけでなく、コンポーネントが読み込まれるのを待ってアイテムプロパティを介して手動で設定する代わりに、setSourceを使用して設定できるオブジェクトのプロパティにも適用されます(Qtには、このメソッドの4番目のバージョンはありません)。



非ビジュアルアイテムのダウンロード


QtQuick 2.0では、ローダーは視覚要素だけでなくロードする機能を追加しました。 たとえば、この方法でQtObjectに基づいて要素をロードできます。



main.qml:

 import QtQuick 2.0 Item { id: main width: 360 height: 360 Loader { id: container anchors.fill: parent source: "Element.qml" onLoaded: console.log(item.text) } }
      
      







Element.qml:

 import QtQuick 2.0 QtObject { property string text: "hello!" }
      
      







起動すると、「hello!」がコンソールに表示されます。



短い要約


ローダーは、他のファイルからqmlコンポーネントをロードし、現在のqmlファイルの領域で定義されたコンポーネントを使用できます。 選択した方法に応じて、作成プロセスの一部の実行を1回延期してオブジェクトの作成を高速化するか、必要になるまでオブジェクトを作成するすべての操作を延期することができます。



qmlは宣言型言語であるという事実にもかかわらず、多くのことを命令的に実行することができます。これは、状況によっては役立つかもしれませんが、多少の複雑さとコード量の増加を伴います。 Qtの最新バージョンではない場合、この方法はライブラリの制限を回避するのに役立ちます。




All Articles