QMLエンジンの内部。 パート1:ファイルをダウンロードする

この翻訳のパート2 )シリーズの記事では、QMLエンジンの内部を見て、内部作業の機能のいくつかを明らかにしますQt5のQtQuickバージョン、QtQuick 2.0に基づいています。



ほとんどの人は、QMLファイルのすべての要素が特定のC ++クラスに依存していることを知っています。 QMLファイルがロードされると、QMLエンジンは何らかの方法でファイル内のすべての要素に対して1つのC ++オブジェクトを作成します。 この投稿では、C ++オブジェクトの完全なツリーを含むテキストファイルの読み取りからQMLエンジンがどのように移動するかを見ていきます。 Qtのドキュメントには、QMLとC ++の相互作用に関する詳細な説明を含むセクションがあり、読むのに時間を費やす価値があります。 この一連の記事では、ユーザーがドキュメントに記載されている内容を読んで理解していることを前提としています。





この記事では、特別なことは何もしませんが、QMLの興味深い部分を含む例を使用します。



import QtQuick 2.0 Rectangle { id: root width: 360 height: width + 50 color: "lightsteelblue" property alias myWidth: root.width property int counter: 1 function reactToClick() { root.counter++ } Text { id: text text: qsTr("Hello World: " + counter) anchors.centerIn: parent } MouseArea { id: mouseArea anchors.fill: parent onClicked: { reactToClick() } } }
      
      





このファイルは、Rectangle、Text、およびMouseAreaの3つの要素で構成されています。 これらは、C ++クラスのQQuickRectangleQQuickText 、およびQQuickMouseAreaに対応しています。 さらに、これらのクラスはQMLにのみエクスポートされ、プライベートであり、C ++から直接Qtユーザーにアクセスできません。 要素は、 QMLシーングラフQMLシーンツリー)を使用してOpenGLを介して画面に描画されます。 イベントが描画および処理される順序はQQuickViewによって決定されます 。 1対1のQMLファイルは、生成されたC ++オブジェクトツリーに対応します。これは、 Gammarayと呼ばれるQt KDABチームによって開発されたツールを使用して確認できます。



画像



予想どおり、QQuickMouseAreaおよびQQuickTextクラスはオブジェクトツリーに表示されます。 しかし、QQuickRectangle_QML_0とは何ですか? そのようなC ++クラスは、Qtのソースコードには存在しません! 後の投稿でこれに戻りますが、今のところは、QQuickRectangleオブジェクトが使用されたと仮定します。



先に進み、 QMLプロファイラーでアプリケーションを実行しましょう。

画像



ご覧のとおり、時間の大部分は作成フェーズに入ります。 そしてかなり-描画の段階(絵画)で、その結果が画面に表示されます。 しかし、コンパイル段階は何ですか? それはマシンまたはバイトコードを意味しますか? ファイルアップロードアルゴリズムをもう少し詳しく見てみましょう。



QMLファイルをロードする手順



QMLファイルのダウンロードは、3つの独立した段階に分けられます。これについては、次のセクションで検討します。



解析


まず、QQmlScript :: Parserを使用してQMLファイルを解析します。 ほとんどの内部パーサールールは、文法ファイルから自動的に生成されます。 この例の抽象構文ツリー(AST)は次のようになります。

画像

(画像はgraphvizとこのパッチを使用して生成されました)



最初、ASTはかなり低いレベルで動作し、その次のステップで、より高いレベルで、 オブジェクト(オブジェクト)プロパティ(プロパティ)および値(値)の構造に変わります 。 これはAST :: Visitorによって行われます。 このレベルでは、オブジェクトはQML要素に対応し、「color」や「lightsteelblue」などのプロパティと値のペアはQML要素のデータプロパティと値に対応します。 この段階でonClickedのようなシグナルハンドラでさえ、プロパティ/値のペアに過ぎません。この場合、値はJavaScript関数の本体です。



編集


理論的には、オブジェクト、プロパティ、および値の構造を持ち、これらのQML要素に関連付けられたC ++オブジェクトを既に作成し、適切な値をそれらに割り当てることができます。 ただし、オブジェクト、プロパティ、および値はまだかなり粗雑であり、C ++オブジェクトを作成する前に後処理が必要です。 後処理は、 QQmlCompilerオブジェクトによって実行されます。これは、プロファイラーの「コンパイル」ステージの意味を説明しています。 コンパイラーは、指定されたQMLファイルのQQmlCompiledDataオブジェクトを作成します。



QQmlCompiledDataを使って作業し、 そこからC ++オブジェクトを作成する方が、オブジェクト、プロパティ、値を直接操作するよりもはるかに高速です。 前述のように、オブジェクトツリーは個々のQMLファイルごとに構築されます。 他のQMLファイルで広く使用されているButton.qmlなどのQMLファイルを繰り返し使用する場合、QQmlCompiledDataオブジェクトは1回だけコンパイルされ、メモリに保存され、Buttonファイルが含まれるたびにC ++オブジェクトを作成するために使用されますアプリケーションの解析中の.qml。 この後、作成段階が始まります。これは、プロファイラーウィンドウで確認できます。



要約すると、各QMLファイルの解析とコンパイルは1回だけ行われ、その後QQmlCompiledDataオブジェクトを使用してC ++オブジェクトをすばやく作成します。



作成


QQmlCompiledDataについては詳しく説明しませんが、1つ注意すべき点があります。QByteArrayバイトコードメンバー変数です。 C ++オブジェクトの作成手順とプロパティへの値の適切な割り当てはバイトコードとしてコンパイルされ、バイトコードインタープリターによって解釈されます(トランスレーターから:インタープリターは解釈され、解釈されますが、... =ではありません )。 バイトコードには一連の命令が含まれ、QQmlCompiledDataの残りのコンテンツは、命令の実行時に補助データとしてのみ使用されます。



作成段階で、バイトコードはQQmlVMEクラスによって解釈されます。 インタープリターのQQmlVME :: run()関数は、大きなswitchステートメントに基づいてバイトコード命令を順次実行します。 フラグQML_COMPILER_DUMP = 1でアプリケーションを起動すると、個々のバイトコード命令が表示されます。

 Index Operation Data1 Data2 Data3 Comments ------------------------------------------------------------------------------- 0 INIT 4 3 0 0 1 INIT_V8_BINDING 0 17 2 CREATECPP 0 3 STORE_META 4 SETID 0 "root" 5 BEGIN 16 6 STORE_INTEGER 45 1 7 STORE_COLOR 41 "ffb0c4de" 8 STORE_COMPILED_BINDING 10 2 0 9 STORE_DOUBLE 9 360 10 FETCH_QLIST 2 11 CREATE_SIMPLE 32 12 SETID 1 "text" 13 BEGIN 16 14 STORE_V8_BINDING 43 0 0 15 FETCH 19 16 STORE_COMPILED_BINDING 17 1 1 17 POP 18 STORE_OBJECT_QLIST 19 CREATE_SIMPLE 32 20 SETID 2 "mouseArea" 21 BEGIN 16 22 STORE_SIGNAL 42 2 23 FETCH 19 24 STORE_COMPILED_BINDING 16 0 1 25 POP 26 STORE_OBJECT_QLIST 27 POP_QLIST 28 SET_DEFAULT 29 DONE -------------------------------------------------------------------------------
      
      









VMEにはオブジェクトのスタックがあり、STORE_ *タイプのすべての命令は最上位にあるオブジェクトで動作します。 FETCHは特定のQObjectをスタックの一番上に配置し、POPは一番上のオブジェクトを削除します。 すべての命令は、数値インデックスを広範囲に使用します。たとえば、STORE_COLORステートメントは、ターゲットQObjectであるメタプロパティobject.dinaryのインデックスであるプロパティ41に書き込みます。



要約すると、QMLファイルがコンパイルされた後、そのC ++オブジェクトのインスタンスを作成するのは、送信されたコンパイル済みデータから生成されたバイトコードを実行するだけです。



おわりに



このメモの最後に、QMLファイルの解析、処理、およびコンパイル方法を紹介しました。 そして、VME​​が関連オブジェクトを作成する方法。 QMLエンジンについて興味深いことを学んだことを願っています。



次の投稿までお楽しみに。QMLでバインディングがどのように機能するかを見ていきます。



翻訳者から:同じやり方で続けるか、停止するか? 過去の 翻訳に関するコメントの控えめな数から判断すると、このトピックはHabrの聴衆にとってあまり興味深いものではありません。



PS:そして、はい、私からの翻訳者はまあまあであることを知っていますが、私は最善を尽くします=)エラーとコメント-私は午後に尋ねます。



All Articles