ご存知かもしれませんが、QMLドキュメントにはそれぞれ暗黙的なインポートが設定されています。同じディレクトリにある他のQMLドキュメントは、インポートなしで使用することができます。これは、記述する必要のある定型文の量を大幅に削減する、非常に便利な機能です。通常、QMLファイルが属するモジュール自体をインポートする必要はありません。
この機能は、暗黙のインポートによってファイルが属するモジュールが取得されない場合、明らかに有用性が低下します。ここであなたは「そんなことが起こり得るのか?」と私に尋ねるでしょう。私は「そんなことは起こりません!」と答えたいところですが、過去に戻って CMake API を制限することはできないため、起こり得ることを認めざるを得ません。明らかに、QML モジュールについて書いているとき、私はこのケースを考えていませんでした。どの例でも、このケースは実行されていません。
しかし、私よりも想像力豊かな人々は、本来の目的とは異なる方法で QML モジュール用の CMake API を使用する方法を知っていました。教育目的のために、次に何が起こるのかを見てみましょう。親の許可なしにこれを行ってはいけません。
それでは、QML モジュールをそのファイルの暗黙的なインポートと異なるものにする方法を説明します。
myProject
| - CMakeLists.txt
| - main.cpp
| - some_qml_type.h
| - some_qml_type.cpp
| - qml
| - main.qml
| - Pickles.qml
上記のプロジェクト構造では、CMakeLists.txtでqt_add_qml_moduleを呼び出しているものとします。また、このように定義されたQMLモジュールには、main.qmlとPickles.qmlが含まれています。main.qmlとPickles.qmlの暗黙的なインポートは「qml」ディレクトリです。しかし、それらのモジュールは「myProject」ディレクトリで定義されています。ここで、main.qmlまたはPickles.qmlで、some_qml_type.hで宣言されたものを使用したい場合は、myProjectを明示的にインポートする必要があります。おめでとうございます!
なぜでしょうか? 理由は簡単です。qmldirファイルはmyProjectの1つ上のディレクトリにあるため、main.qmlとPickles.qmlはqmldirファイルを自分たちのディレクトリで見つけることができません。同じディレクトリにqmldirファイルがない場合、暗黙的なインポートは、そこに存在するQMLファイルのファイル名のみを使用して構築されます。この場合、C++定義の型を挿入する余地はありません。
また、CMakeLists.txtに次の行を追加すると、さらに楽しくなります。
set_source_files_properties(qml/Pickles.qml PROPERTIES
QT_QML_SOURCE_TYPENAME Chocolate
)
これで、main.qml では、隣にある Pickles.qml で定義されている「Pickles」というコンポーネントを、これまでと同様に使用することができます。ただし、myProject をインポートした場合、「Pickles」というコンポーネントは取得できません。代わりに、同じ内容の「Chocolate」というコンポーネントが取得されます。myProject をインポートしていない main.qml では、この「Chocolate」は取得できません。素晴らしいと思いませんか?
しかし、まだ終わりではありません。名前付きモジュール経由でインポートされたシングルトンを参照する型名は、同じモジュール内の暗黙のインポート経由でアクセスされた場合は通常の型を参照する、ということをご存知でしたか? これを行う正確な方法は、読者(保護者の監視下にある)の練習問題として残しておきます。 ヒント:思ったほど簡単ではありません。 正しい解答をコメントに投稿した最初の1人に、ピクルスをお送りします。
もちろん、これらの効果はすべて機能です。お楽しみください。バグレポートで私を悩ませないでください。お楽しみはここまでです。真面目な部分に戻りましょう。
悲しい真実ですが、公式のサンプルの多くは、まさに上記の構造を示しており、アプリケーションのルートと QML ファイルの間に「qml」という追加のディレクトリがあります。Qt5 では、適切な名前の QML モジュールを作成するのが難しかったため、コードを構造化し、QML ファイルを C++ コードから分離するには、これが良い方法でした。 CMake への移植の際、この構造の問題はしばらくの間、検出されませんでした。 現在では、この構造が皆さんのプロジェクトに徐々に浸透し、レガシーとして定着しています。
しかし、人々は意図的にこのようなサブディレクトリを作成することもあります。QMLモジュールに内部構造を持たせることは、大きなモジュールをより小さな部分に分割し、可読性を向上させることにも役立ちます。これらの部分は、定義上、別々のモジュールであるべきです。しかし、サブディレクトリを追加する方が、モジュールを分割するよりも初期コストが少なくて済みます。結局、CMakeLists.txtを余分に書く必要はなく、URIやモジュールが動的か静的か、リンク方法などを考える必要もありません。もし、上述のような状況に遭遇しないのであれば、大きなモジュールを分割するメリットはないかもしれません。
プロジェクト構造を変更して、QMLファイルの暗黙的なインポートが、それらが属するモジュールと同じになるようにするには、複数の方法があります。
この記事を書いている際に、次のことに気づきました。
モジュールのC++定義の型は暗黙的なインポートから依然としてロードされません。これは明らかにバグです。https://codereview.qt-project.org/c/qt/qtdeclarative/+/541951で修正されています。