スコープと命名解決
QMLのプロパティバインディング、インライン関数、インポートされたJavaScriptファイルは、すべてJavaScriptのスコープ内で実行されます。スコープは式がどの変数にアクセスできるかを制御し、2つ以上の名前が衝突した場合にどの変数が優先されるかを制御します。
JavaScript 組み込みのスコープ機構は非常に単純であるため、QML では言語拡張に 適合するようにスコープ機構を拡張しています。
JavaScript のスコープ
QML のスコープ拡張は、JavaScript の自然なスコープを妨げるものではありません。JavaScriptプログラマは、関数やプロパティバインディング、インポートしたJavaScriptファイルをQMLでプログラミングする際に、既存の知識を再利用することができます。
次の例では、addConstant() メソッドは、QML オブジェクトのa やb プロパティの値に関係なく、プログラマーが期待するように、渡されたパラメータに 13 を追加します。
QtObject { property int a: 3 property int b: 9 function addConstant(b) { var a = 13; return b + a; } }
QMLはJavaScriptの通常のスコープルールを尊重し、バインディングにも適用します。この全く邪悪で忌まわしいバインディングは QML オブジェクトのa プロパティに 12 を代入します。
QMLのすべてのJavaScript式、関数、ファイルは独自の変数オブジェクトを持ちます。あるファイルで宣言されたローカル変数が、別のファイルで宣言された ローカル変数と衝突することはありません。
型名とインポートされたJavaScriptファイル
QMLドキュメントには、そのドキュメントから見える型名やJavaScriptファイルを定義するimport文が含まれています。QMLの宣言自体で使用されるだけでなく、JavaScriptのコードでも、付属のプロパティや列挙値にアクセスする際に型名が使用されます。
インポートの効果は、QML文書内のすべてのプロパティバインディングやJavaScript関数に適用されます。次の例は、いくつかの列挙値にアクセスし、インポートされたJavaScript関数を呼び出す単純なQMLファイルです。
import QtQuick 2.0 import "code.js" as Code ListView { snapMode: ListView.SnapToItem delegate: Component { Text { elide: Text.ElideMiddle text: "A really, really long string that will require eliding." color: Code.defaultColor() } } }
バインディングスコープオブジェクト
プロパティバインディングを持つオブジェクトは、バインディングのスコープオブジェクトとして知られています。次の例では、Item オブジェクトがバインディングのスコープオブジェクトです。
Item { anchors.left: parent.left }
バ イ ンデ ィ ン グは、 ス コ ープオブジ ェ ク ト のプ ロ パテ ィ に無条件でア ク セ ス で き ます。先ほどの例では、バインディングはItem のparent プロパティに直接アクセスしています。QMLはJavaScriptに対してより構造化されたオブジェクト指向のアプローチを導入しているため、JavaScriptのthis プロパティを使用する必要はありません。
バインディングからアタッチドプロパティにアクセスする際には、スコープオブジェクトとの相互作用のために注意が必要です。概念的に、 添付プ ロ パテ ィ はすべてのオブジ ェ ク ト 上に存在 し ます。その結果、修飾されていないアタッチド・プロパティを読み込むと、常にスコープ・オブジェクト上のアタッチド・プロパティに解決されますが、これは必ずしもプログラマーの意図したものではありません。
例えば、PathView 型は、そのデリゲートに、パス内の位置に応じて補間された値のプロパティをアタッチします。PathView は、これらのプロパティをデリゲート内のルート・オブジェクトにのみ意味のある形で付加するため、これらにアクセスするサブ・オブジェクトは、以下に示すように、ルート・オブジェクトを明示的に修飾しなければなりません。
Image オブジェクトがroot の接頭辞を省略すると、設定されていないPathView.scale のアタッチド・プロパティに誤ってアクセスしてしまいます。
コンポーネントのスコープ
QML文書内の各QMLコンポーネントは論理的なスコープを定義します。各文書は少なくとも1つのルートコンポーネントを持ちますが、他のインラインサブコンポーネントを持つこともできます。コンポーネントのスコープは、コンポーネント内のオブジェクトIDと、 コンポーネントのルートオブジェクトのプロパティの和です。
Item {
property string title
Text {
id: titletype
text: "<b>" + title + "</b>"
font.pixelSize: 22
anchors.top: parent.top
}
Text {
text: titletype.text
font.pixelSize: 18
anchors.bottom: parent.bottom
}
}上の例では、上部にリッチテキストのタイトル文字列を表示し、下部に同じテキストの小さなコピーを表示する単純なQMLコンポーネントを示しています。最初のText タイプは、表示するテキストを形成する際に、コンポーネントのtitle プロパティに直接アクセスします。ルート型のプロパティに直接アクセスできることで、コンポーネント全体にデータを配布することが簡単になります。
2番目のText 型は、idを使用して1番目のテキストに直接アクセスします。idはQMLプログラマによって明示的に指定されるため、常に他のプロパティ名よりも優先されます(JavaScriptスコープ内のものを除く)。例えば、先ほどの例でバインディングのスコープオブジェクトに titletype というプロパティがあったとしても、titletype のidが優先されます。
コンポーネントインスタンスの階層
QMLでは、コンポーネントインスタンスがそのコンポーネントスコープを連結してスコープ階層を形成しています。コンポーネントインスタンスは先祖のコンポーネントスコープに直接アクセスすることができます。
これを示す最も簡単な方法は、インラインサブコンポーネントのコンポーネントスコープが暗黙のうちに外側のコンポーネントの子としてスコープされていることです。
Item { property color defaultColor: "blue" ListView { delegate: Component { Rectangle { color: defaultColor } } } }
コンポーネントのインスタンス階層によって、デリゲート・コンポーネントのインスタンスはItem タイプのdefaultColor プロパティにアクセスすることができます。もちろん、デリゲート・コンポーネントにdefaultColor というプロパティがあれば、そちらが優先される。
コンポーネントのインスタンス・スコープの階層は、アウトオブライン・コンポーネン トにも及びます。次の例では、TitlePage.qml コンポーネントが2つのTitleText インスタンスを作成しています。TitleText title TitlePageQML は動的スコープ言語であり、使用する場所によってtitle プロパティの解決方法が異なります。
// TitlePage.qml
import QtQuick 2.0
Item {
property string title
TitleText {
size: 22
anchors.top: parent.top
}
TitleText {
size: 18
anchors.bottom: parent.bottom
}
}
// TitleText.qml
import QtQuick 2.0
Text {
property int size
text: "<b>" + title + "</b>"
font.pixelSize: size
}動的スコープは非常に強力ですが、QMLコードの挙動が予測しづらくなるのを防ぐため、 慎重に使用する必要があります。一般的には、2つのコンポーネントがすでに別の方法で緊密に結合されている場合にのみ使用すべきです。再利用可能なコンポーネントを構築する場合には、次のようなプロパティ・インターフェー スを使用することが望ましいでしょう:
// TitlePage.qml
import QtQuick 2.0
Item {
id: root
property string title
TitleText {
title: root.title
size: 22
anchors.top: parent.top
}
TitleText {
title: root.title
size: 18
anchors.bottom: parent.bottom
}
}
// TitleText.qml
import QtQuick 2.0
Text {
property string title
property int size
text: "<b>" + title + "</b>"
font.pixelSize: size
}他のQMLコンポーネントからルートオブジェクトid を参照しない
ルートオブジェクトが定義されているQMLファイルの外から、ルートオブジェクトのid にアクセスすることは避けてください。id の値は、同じドキュメント内でのみ有効であり、他のコンポーネントから参照することは、カプセル化やコンポーネントの境界を壊すことになります。
// Main.qml import QtQuick Item { id: root CustomItem { } } // CustomItem.qml import QtQuick Rectangle { width: root.width height: root.height / 2 color: "red" }
上の例では、root はCustomItem.qml で宣言されていません。このコードは、root が存在するコンテキストで、CustomItem がインスタンス化されるため、まだ動作します。これは、QMLの動的スコープルールで認められています。しかし、これでは外側のスコープに暗黙の依存関係ができてしまい、動的に読み込まれたり、別のコンテキストで使われたりしたときに、コンポーネントの信頼性が低くなり、再利用が難しくなります。また、このパターンは微妙なバグを引き起こす可能性もある。たとえば、スコープチェーン内の別のオブジェクトが同じid を使用すると、期待されたものが影になり、予期しない動作になる可能性があります。
コンポーネントの信頼性と再利用性を高めるために、外部状態へのアクセスは、明示的なプロパティ、プロパティのエイリアス、またはシグナルによってのみ行うようにしましょう。外部スコープid の値に依存するのは避けましょう。
次の例では、動的スコープを明示的なコンポーネントAPIに置き換えています。
// Main.qml import QtQuick import QtQuick.Window Window { id: root width: 400 height: 300 visible: true CustomItem { width: root.width height: root.height boxColor: "blue" } } // CustomItem.qml import QtQuick Item { id: container property alias boxColor: rect.color Rectangle { id: rect width: container.width height: container.height / 2 color: "red" } }
同じルールを、コンポーネント内部でid を使用して宣言されたすべての内部オブジェクトに適用します。
// MyItem.qml import QtQuick Item { Item { id: internalCounter property int count: 5 } } // main.qml import QtQuick MyItem { Component.onCompleted: { console.log(internalCounter.count); } }
上記の例では、id internalCounter に別の QML ファイルからアクセスすると、ReferenceError が発生します。これは、id がドキュメントローカルであり、宣言された QML ファイルの外部からはアクセスできないためです。
内部オブジェクトの状態や振る舞いを公開する必要がある場合は、プロパティ、 プロパティのエイリアス、シグナルなどを用いて明示的に公開します。
以下の例では、ドキュメントローカルなid への直接アクセスに頼らず、明示的なコンポーネント API を用いて内部状態を公開しています。
// MyItem.qml import QtQuick Item { Item { id: internalCounter property int count: 5 } property alias internalCount: internalCounter.count } // main.qml import QtQuick MyItem { Component.onCompleted: { console.log(internalCount); } }
これにより、コンポーネントの境界が明確になり、スケーラビリティとテスト性が向上します。
オーバーライドされたプロパティ
QMLでは、あるオブジェクト宣言で定義されたプロパティ名を、そのオブジェクト宣言を継承した別のオブジェクト宣言で宣言されたプロパティでオーバーライドすることができます。例えば
// Displayable.qml
import QtQuick 2.0
Item {
property string title
property string detail
Text {
text: "<b>" + title + "</b><br>" + detail
}
function getTitle() { return title }
function setTitle(newTitle) { title = newTitle }
}
// Person.qml
import QtQuick 2.0
Displayable {
property string title
property string firstName
property string lastName
function fullName() { return title + " " + firstName + " " + lastName }
}ここでは、title という名前が Displayable の出力テキストの見出しと Person オブジェクトの敬称の両方に与えられています。
オーバーライドされたプロパティは、それが参照されるスコープに従って解決されます。Person コンポーネントのスコープ内、または Person コンポーネントのインスタンスを参照する外部スコープからは、title が Person.qml 内で宣言されたプロパティに解決されます。fullName 関数は、Person 内部で宣言されたtitle プロパティを参照します。
一方、Displayable コンポーネントの内部では、title は Displayable.qml 内で宣言されたプロパティを参照します。getTitle() 関数と setTitle() 関数、および Text オブジェクトのtext プロパティのバインディングはすべて、Displayable コンポーネントで宣言されたtitle プロパティを参照します。
同じ名前を共有しているにもかかわらず、2つのプロパティは完全に分離しています。一方のプロパティのonChangedシグナルハンドラは、同名のもう一方のプロパティの変更によってトリガされることはありません。どちらかのプロパティのエイリアスは、どちらか一方を参照しますが、両方を参照することはできません。
JavaScript グローバルオブジェクト
QML では、混乱を避けるために、グローバルオブジェクトのプロパティと衝突する型、id、プロパティ名を禁止しています。プログラマはMath.min(10, 9) が常に期待通りに動作することを確信することができます!
詳しくはJavaScript ホスト環境を参照してください。
© 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.