QML開発者が知るべき「Item.parent」:基本から応用、トラブルシューティングまで

2025-06-06

具体的には、以下の点を理解することが重要です。

  1. 親子関係の確立: QMLでは、あるItemが別のItemの内部に記述されると、自動的に内側のItemは外側のItemの子となります。このとき、内側のItemparentプロパティは外側のItemを指します。

    例:

    Rectangle { // 親 (parent)
        id: parentRect
        width: 200
        height: 200
        color: "red"
    
        Rectangle { // 子 (child)
            id: childRect
            width: 50
            height: 50
            color: "blue"
            x: 10
            y: 10
            // ここで childRect.parent は parentRect を指す
        }
    }
    
  2. 座標系の基準: 子のItemxywidthheightなどの位置とサイズは、その親Itemの座標系を基準として解釈されます。つまり、childRectx: 10は、parentRectの左端から10ピクセル右という意味になります。

  3. プロパティの継承(一部): opacity(不透明度)やvisible(表示/非表示)など、一部のプロパティは親から子へ継承される場合があります。例えば、親Itemopacity0.5に設定すると、子Itemもその影響を受けて半透明になります。

  4. ライフサイクルと破棄: 親Itemが破棄されると、その子Itemも自動的に破棄されます。これにより、メモリ管理が容易になります。

  5. parentプロパティの利用:

    • 参照: childRect.parentのように、子のItemから親Itemのプロパティやメソッドにアクセスできます。

      Rectangle {
          id: parentRect
          width: 200
          height: 200
          color: "red"
      
          Rectangle {
              id: childRect
              width: 50
              height: 50
              color: "blue"
              x: 10
              y: 10
              MouseArea {
                  anchors.fill: parent
                  onClicked: {
                      console.log("親の幅:", parentRect.width); // childRect.parent.width と同じ
                      // または childRect.parent.width;
                  }
              }
          }
      }
      
    • 親の変更: Item.parentプロパティは読み取り専用ではありません。実行時にItemの親を変更することが可能です。これは、ItemをUIの異なる部分に移動させたり、レイアウトを動的に変更したりする際に非常に便利です。

      例: あるボタンがクリックされたときに、myRectangleの親をcontainer1からcontainer2に変更する。

      Item {
          id: root
      
          Rectangle {
              id: container1
              width: 100; height: 100
              color: "green"
          }
      
          Rectangle {
              id: container2
              x: 150
              width: 100; height: 100
              color: "blue"
          }
      
          Rectangle {
              id: myRectangle
              width: 50; height: 50
              color: "yellow"
              parent: container1 // 最初は container1 の子
          }
      
          Button {
              text: "親を変更"
              onClicked: {
                  if (myRectangle.parent === container1) {
                      myRectangle.parent = container2;
                  } else {
                      myRectangle.parent = container1;
                  }
              }
          }
      }
      

      注意点: 親を変更すると、子のxyなどのプロパティが新しい親の座標系に合わせて再計算されるため、見かけ上の位置が変わる可能性があります。



Item.parentに関する一般的なエラーとトラブルシューティング

座標系のずれ (Unexpected Positioning)

問題: 親の Item の位置やサイズを変更したときに、子の Item が意図しない場所に移動してしまう。または、x, y プロパティを設定しても期待通りの位置にならない。

原因:

  • 異なる親に付け替えた場合、子の x, y は新しい親の座標系で解釈されるため、見た目の位置が大きく変わることがあります。
  • 子の Itemx, y プロパティは、常に親の座標系を基準としています。親が移動したりサイズが変わったりすると、それに合わせて子の絶対位置も変わります。

トラブルシューティング:

  • 動的な親の変更時の調整: Item.parent をスクリプトで変更する場合、変更後に子の x, y を再設定して、新しい親の座標系に合わせて適切な位置に配置し直す必要があります。
  • アンカー (Anchors) の活用: レイアウトを相対的に指定するのにアンカーは非常に強力です。parent に基づく相対的な位置決めをしたい場合は、anchors.fill: parentanchors.centerIn: parent などを積極的に利用しましょう。
  • 絶対位置の考慮: 子の絶対的な画面上の位置を固定したい場合は、親の動きに合わせて子の x, y を動的に調整する必要があります。mapToItem(), mapFromItem(), mapToScene(), mapFromScene() などの座標変換関数が役立ちます。

見えない、またはクリップされる (Invisible or Clipped Items)

問題: 子の Item が表示されない、または一部しか表示されない。

原因:

  • 子の Itemz プロパティが低すぎ、他の Item の下に隠れてしまっている。
  • 親の visible プロパティが false に設定されている。
  • 親の Itemclip: true が設定されており、子の Item が親の境界外に描画されているためクリップされている。
  • 親の Itemwidth または height0 である、または非常に小さい。

トラブルシューティング:

  • zオーダーの確認: z プロパティを使用して Item の描画順序を調整します。値が大きいほど手前に描画されます。
  • 表示設定の確認: 親と子の両方の visible プロパティが true であることを確認します。
  • クリップ設定の確認: 親の clip プロパティを確認し、必要に応じて false に設定するか、子の位置を親の境界内に収めるように調整します。
  • 親のサイズ確認: 親の Itemwidthheight が適切に設定されているか確認します。

イベントの伝播問題 (Event Propagation Issues)

問題: 子の Item 上でのマウスやタッチイベントが期待通りに発生しない、または親の Item のイベントが子に影響を与えてしまう。

原因:

  • MouseArea.propagateComposedEvents の設定が意図しないイベント伝播を引き起こしている。
  • MouseArea などが重なっており、意図しない Item がイベントを処理している。

トラブルシューティング:

  • MouseArea.enabled / MouseArea.visible: 条件によっては MouseArea を無効化したり、非表示にしたりすることで、イベント処理を制御できます。
  • MouseArea.propagateComposedEvents: イベントを親に伝播させたくない場合は MouseArea { propagateComposedEvents: false; ... } のように設定します。逆に、複数の MouseArea でイベントを処理させたい場合は true に設定します。
  • MouseArea の配置: MouseArea は、それが適用される Item の上に重ねて配置されることが一般的です。イベントを拾いたい領域と、MouseAreaanchors.fill などが一致しているか確認します。

メモリリーク/二重解放 (Memory Leaks / Double Free)

問題: アプリケーションがクラッシュする、またはメモリ使用量が増加する。

原因:

  • new で作成した QObject に親を設定した場合、親が削除されるときに子が自動的に削除されます。この子を自分で delete してしまうと、二重解放 (double free) が発生し、クラッシュの原因になります。
  • C++で QObject を継承したオブジェクトを動的に作成し、手動で parent を設定しなかった場合、メモリ管理を自分で行う必要があります。

トラブルシューティング:

  • deleteLater() の使用: シグナル/スロット接続など、Qtのイベントループ内でオブジェクトを安全に削除したい場合は、deleteLater() を使用するのが一般的です。これにより、現在のイベントループが完了した後にオブジェクトが削除されます。
  • Qtの親子関係によるメモリ管理を理解する:
    • QMLで作成されたItemは、QMLエンジンによって自動的に親子関係に基づいてメモリ管理されます。明示的にdestroy()を呼ばない限り、通常は手動で解放する必要はありません。
    • C++でnewを使ってQObjectを作成し、コンストラクタで親を指定した場合 (MyObject *obj = new MyObject(parentObject);)、parentObjectが削除されるときにobjも自動的に削除されます。この場合、objを明示的にdeleteしてはいけません。
    • newを使ってQObjectを作成し、親を指定しなかった場合 (MyObject *obj = new MyObject();)、objは「ルート」オブジェクトとなり、手動でdelete obj;を呼び出す必要があります。

動的な親の変更時のバインディングの問題 (Binding Issues with Dynamic Parent Changes)

問題: Item.parent を動的に変更した後に、子のプロパティバインディングが正しく機能しない。

原因:

  • QMLのバインディングは、多くの場合、オブジェクトが最初にインスタンス化されたときのコンテキストに基づいて解決されます。親が変更されたときに、子のプロパティが新しい親のプロパティに自動的に再バインドされない場合があります。

トラブルシューティング:

  • 状態 (States) と ParentChange の利用: より複雑なUIの状態変化を伴う親の変更には、QMLの StateParentChange エレメントを活用すると、より宣言的に動作を記述できます。
    Item {
        id: root
    
        Rectangle { id: containerA; width: 100; height: 100; color: "red" }
        Rectangle { id: containerB; x: 150; width: 100; height: 100; color: "blue" }
    
        Rectangle {
            id: movableRect
            width: 50; height: 50; color: "yellow"
        }
    
        StateGroup {
            id: stateGroup
            states: [
                State {
                    name: "inA"
                    ParentChange {
                        target: movableRect
                        parent: containerA
                    }
                },
                State {
                    name: "inB"
                    ParentChange {
                        target: movableRect
                        parent: containerB
                    }
                }
            ]
        }
    
        Button {
            text: "Move"
            onClicked: {
                if (stateGroup.currentState === "inA") {
                    stateGroup.currentState = "inB";
                } else {
                    stateGroup.currentState = "inA";
                }
            }
        }
    }
    
  • 明示的なバインディングの再設定: 親を変更した後に、必要に応じて子のプロパティを新しい親のプロパティに明示的に再バインドするスクリプトを書くことを検討します。

ルートオブジェクトの親 (Root Object's Parent)

問題: アプリケーションのルートとなる Item (例: ApplicationWindow の中のトップレベルの Rectangle など) の parentnull または undefined になる。

原因:

  • QMLのルート要素は、通常、親を持ちません。これは意図された動作です。

トラブルシューティング:

  • これはエラーではありません。ルート要素は親を持たないため、parent プロパティはnullになります。もしルート要素のparentを参照しようとしてエラーになる場合は、それがルート要素であることを認識し、親へのアクセスを試みないようにロジックを調整します。
  • ドキュメントの参照: Item.parent や関連するプロパティ、QML のライフサイクルに関するQtの公式ドキュメントを常に参照してください。
  • 最小再現コード: 問題が発生した場合は、その問題を再現できる最小限のQMLコードを作成してみてください。これにより、他の要因を排除し、問題の原因を絞り込むことができます。
  • Qt Creator の QML Debugger: Qt Creatorには強力なQMLデバッガーが搭載されており、実行中のQMLオブジェクトツリー、プロパティの値、バインディングなどを視覚的に確認できます。これで親子関係やプロパティの値を調べると、問題の特定に役立ちます。
  • console.log() を活用する: Itemx, y, width, height, parent のIDなどをconsole.log() で出力し、実行時の値を確認することが非常に有効です。


基本的な親子関係と座標系

最も基本的な例です。子の Rectangle は親の Rectangle の中に定義され、自動的にその子となります。子の xy は親の左上を基準とします。

// main.qml
import QtQuick

ApplicationWindow {
    width: 400
    height: 300
    visible: true
    title: "Parent Example 1: Basic Parenting"

    // 親のRectangle
    Rectangle {
        id: parentRect
        width: 200
        height: 150
        color: "lightsteelblue"
        x: 50
        y: 50

        Text {
            anchors.centerIn: parent
            text: "私は親です (parentRect)"
            font.pixelSize: 14
        }

        // 子のRectangle
        Rectangle {
            id: childRect
            width: 80
            height: 60
            color: "salmon"
            x: 20 // 親の左端から20ピクセル右
            y: 20 // 親の上端から20ピクセル下

            Text {
                anchors.centerIn: parent
                text: "私は子です (childRect)"
                font.pixelSize: 12
            }

            // 子から親のプロパティを参照
            MouseArea {
                anchors.fill: parent
                onClicked: {
                    console.log("子のRectangleがクリックされました。");
                    console.log("私の親のID:", childRect.parent.id); // "parentRect" が出力される
                    console.log("私の親の幅:", childRect.parent.width); // 200 が出力される
                }
            }
        }
    }
}

解説:

  • childRectx: 20, y: 20 は、parentRect の左上角からの相対位置です。もし parentRectx: 100, y: 100 に移動した場合、childRect の画面上の絶対位置は x: 120, y: 120 となります。
  • childRect.parentparentRect オブジェクトを指します。
  • childRectparentRect の内部に定義されているため、自動的に parentRect の子になります。

動的な親の変更

実行時に Item の親を変更する例です。これは、UI要素を異なるコンテナ間で移動させたい場合などに非常に役立ちます。

// main.qml
import QtQuick
import QtQuick.Controls

ApplicationWindow {
    width: 400
    height: 300
    visible: true
    title: "Parent Example 2: Dynamic Parent Change"

    Rectangle {
        id: containerA
        width: 150
        height: 150
        color: "lightgreen"
        x: 20
        y: 20

        Text {
            anchors.centerIn: parent
            text: "コンテナA"
        }
    }

    Rectangle {
        id: containerB
        width: 150
        height: 150
        color: "lightblue"
        x: 200
        y: 20

        Text {
            anchors.centerIn: parent
            text: "コンテナB"
        }
    }

    // 親を動的に変更するオブジェクト
    Rectangle {
        id: movableRect
        width: 80
        height: 80
        color: "yellow"
        // 最初は containerA の子として設定
        parent: containerA
        // 親の変更に伴い、位置を中央に調整する
        anchors.centerIn: parent

        Text {
            anchors.centerIn: parent
            text: "動く四角"
            font.pixelSize: 12
        }
    }

    Button {
        text: "親を切り替える"
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: movableRect.bottom
        y: 20

        onClicked: {
            if (movableRect.parent === containerA) {
                movableRect.parent = containerB;
            } else {
                movableRect.parent = containerA;
            }
            // 親が変わると座標系も変わるので、位置を再調整する
            // anchors.centerIn: parent; が設定されているので、自動的に中央に配置される
            // もし anchors を使わない場合は、手動で x, y を設定し直す必要がある
        }
    }
}

解説:

  • もし anchors を使わず x, y で位置を指定していた場合、親を変更しただけでは movableRect の見かけ上の位置は変わらず、新しい親の左上を基準に同じ x, y に配置されることになります。その場合、手動で movableRect.x = (movableRect.parent.width - movableRect.width) / 2; のように位置を再計算する必要があるでしょう。
  • 親が変更されると、movableRectanchors.centerIn: parent というバインディングが再評価され、新しい親のコンテナ内で中央に配置されます。
  • movableRectparent プロパティを containerA または containerB に動的に変更しています。

C++側からQMLの Item オブジェクトの親を変更することも可能です。これは、複雑なロジックやネイティブコードとの連携が必要な場合に利用されます。

QML側 (main.qml):

// main.qml
import QtQuick
import QtQuick.Controls

ApplicationWindow {
    width: 400
    height: 300
    visible: true
    title: "Parent Example 3: C++ Parent Change"

    Rectangle {
        id: containerC
        width: 150
        height: 150
        color: "lightcoral"
        x: 20
        y: 20

        Text {
            anchors.centerIn: parent
            text: "コンテナC"
        }
    }

    Rectangle {
        id: containerD
        width: 150
        height: 150
        color: "lightskyblue"
        x: 200
        y: 20

        Text {
            anchors.centerIn: parent
            text: "コンテナD"
        }
    }

    Rectangle {
        id: cppControlledRect
        width: 80
        height: 80
        color: "purple"
        // 初期状態では親を設定しない(または、どちらかのコンテナに設定してもよい)
        // parent: containerC // 例えば、最初からcontainerCの子にしておく
        anchors.centerIn: parent // 親が設定されれば中央に配置される
        visible: false // 最初は非表示にしておく

        Text {
            anchors.centerIn: parent
            text: "C++制御"
            color: "white"
            font.pixelSize: 12
        }
    }

    Button {
        text: "C++で親を変更"
        anchors.horizontalCenter: parent.horizontalCenter
        anchors.top: containerC.bottom
        y: 20
        onClicked: {
            // C++側で定義されたメソッドを呼び出す
            myCppHandler.changeParent();
        }
    }
}

C++側 (.pro, .h, .cpp):

parent_example.pro:

QT += quick controls

SOURCES += \
    main.cpp \
    mycpphandler.cpp

HEADERS += \
    mycpphandler.h

QML_IMPORT_PATH += .

mycpphandler.h:

#ifndef MYCPPHANDLER_H
#define MYCPPHANDLER_H

#include <QObject>
#include <QQmlEngine> // QMLエンジンの参照のために必要
#include <QQuickItem> // QQuickItemの参照のために必要

class MyCppHandler : public QObject
{
    Q_OBJECT
    Q_PROPERTY(bool isInContainerC READ isInContainerC WRITE setIsInContainerC NOTIFY isInContainerCChanged FINAL)

public:
    explicit MyCppHandler(QQmlEngine *engine, QObject *parent = nullptr);

    bool isInContainerC() const { return m_isInContainerC; }
    void setIsInContainerC(bool newIsInContainerC);

signals:
    void isInContainerCChanged();

public slots:
    void changeParent();

private:
    QQmlEngine *m_engine;
    bool m_isInContainerC;
};

#endif // MYCPPHANDLER_H

mycpphandler.cpp:

#include "mycpphandler.h"
#include <QDebug>
#include <QQmlComponent> // QMLコンポーネントをロードするために必要

MyCppHandler::MyCppHandler(QQmlEngine *engine, QObject *parent)
    : QObject(parent)
    , m_engine(engine)
    , m_isInContainerC(true) // 初期状態をコンテナCに設定
{
}

void MyCppHandler::setIsInContainerC(bool newIsInContainerC)
{
    if (m_isInContainerC == newIsInContainerC)
        return;
    m_isInContainerC = newIsInContainerC;
    emit isInContainerCChanged();
}

void MyCppHandler::changeParent()
{
    // QMLエンジンからルートコンテキストを取得
    QQmlContext *rootContext = m_engine->rootContext();
    if (!rootContext) {
        qWarning() << "Root context not found!";
        return;
    }

    // IDでQMLオブジェクトを検索
    // QMLからC++にQQuickItem*を直接渡す方がより堅牢ですが、ここではID検索の例として示します。
    QQuickItem *cppControlledRect = rootContext->findChild<QQuickItem*>("cppControlledRect");
    QQuickItem *containerC = rootContext->findChild<QQuickItem*>("containerC");
    QQuickItem *containerD = rootContext->findChild<QQuickItem*>("containerD");

    if (!cppControlledRect || !containerC || !containerD) {
        qWarning() << "One or more QML items not found!";
        return;
    }

    // 表示を有効にする
    cppControlledRect->setVisible(true);

    if (m_isInContainerC) {
        // 現在コンテナCの子であれば、コンテナDの子にする
        cppControlledRect->setParentItem(containerD);
        qDebug() << "Changed parent to containerD";
        setIsInContainerC(false);
    } else {
        // 現在コンテナDの子であれば、コンテナCの子にする
        cppControlledRect->setParentItem(containerC);
        qDebug() << "Changed parent to containerC";
        setIsInContainerC(true);
    }

    // 親の変更後、子の位置を新しい親の中央に調整する(QMLのanchorsが自動的に再評価される)
    // C++側で手動で位置を調整することも可能ですが、QMLのアンカーがより宣言的です。
    // cppControlledRect->setX((cppControlledRect->parentItem()->width() - cppControlledRect->width()) / 2);
    // cppControlledRect->setY((cppControlledRect->parentItem()->height() - cppControlledRect->height()) / 2);
}

main.cpp:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext> // QMLコンテキストにC++オブジェクトを公開するために必要
#include "mycpphandler.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    QQmlApplicationEngine engine;

    // C++オブジェクトをQMLコンテキストに公開
    // myCppHandlerという名前でQMLからアクセス可能になる
    MyCppHandler *myCppHandler = new MyCppHandler(&engine, &engine); // engineを親にすることで、engineが破棄されるときにmyCppHandlerも自動的に破棄される
    engine.rootContext()->setContextProperty("myCppHandler", myCppHandler);

    const QUrl url(u"qrc:/parent_example/main.qml"_qs);
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreationFailed,
                     &app, []() { QCoreApplication::exit(-1); },
                     Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

解説:

  • C++オブジェクトは engine.rootContext()->setContextProperty() を使用してQMLに公開されます。
  • QML側では、myCppHandler.changeParent() を呼び出すことでC++のロジックを実行します。
  • QQuickItem::setParentItem() メソッドを使用して、QMLオブジェクトの親をC++側から変更します。
  • changeParent() メソッド内で、QMLの ItemQQmlContext::findChild() でIDから取得します。
  • MyCppHandler クラスを定義し、changeParent() スロットを作成します。


anchors (アンカー) を使用したレイアウト

Item.parent は要素がどのツリーの子であるかを定義しますが、anchors はその親に対する相対的な位置とサイズを宣言的に指定するための強力なメカニズムです。多くの場合、Item.parent を明示的に操作する代わりに anchors を使用してレイアウトを構築します。

特徴:

  • 強力な制約: 上下左右中央、ベースラインなど、多様なアンカーポイントで柔軟なレイアウトが可能。
  • 自動調整: 親のサイズや位置が変更されると、子も自動的に再配置・リサイズされる。
  • 宣言的: レイアウトの意図がコードから読み取りやすい。

:

Rectangle {
    width: 300
    height: 200
    color: "lightgray"

    Rectangle {
        id: childRect
        width: 100
        height: 80
        color: "red"

        // childRectの親(このRectangle)の中央に配置
        anchors.centerIn: parent
    }

    Rectangle {
        width: 50
        height: 50
        color: "blue"

        // childRectの右に10ピクセルのマージンを開けて配置
        anchors.left: childRect.right
        anchors.leftMargin: 10
        anchors.verticalCenter: childRect.verticalCenter
    }
}

Item.parent との関連: anchors はデフォルトで自身の parent を基準としますが、anchors.right: someOtherItem.left のように、直接的な親子関係にない他の Item を基準にすることもできます。ただし、その場合でも、最終的な描画位置は自身の parent の座標系内で計算されます。

レイアウトマネージャー (Layouts) を使用したレイアウト

anchors は個々の Item の配置に適していますが、より複雑なグリッド状やリスト状のレイアウトには、専用のレイアウトマネージャーが非常に便利です。これらは Item の集合を自動的に配置・整列します。

主なレイアウトマネージャー:

  • StackLayout: 子を重ねて表示し、一度に一つだけ表示する(タブビューなど)。
  • Flow: 子を折り返しながら並べる(ワードラップのように)。
  • Grid: 子をグリッド状に並べる。
  • Column: 子を縦一列に並べる。
  • Row: 子を横一列に並べる。

特徴:

  • レスポンシブデザイン: 親のサイズ変更に自動的に対応できる。
  • 間隔 (spacing)配置 (alignment) を一括で設定できる。

:

import QtQuick.Layouts // Layoutsモジュールをインポート

ColumnLayout { // ColumnLayoutはItem.parentの代替ではなく、追加のレイアウトメカニズム
    width: 300
    height: 200
    spacing: 10 // 子要素間の間隔

    Rectangle {
        width: 100
        height: 50
        color: "red"
    }

    Rectangle {
        width: 120
        height: 60
        color: "green"
    }

    Rectangle {
        width: 80
        height: 40
        color: "blue"
    }
}

Item.parent との関連: レイアウトマネージャー自身も Item であり、通常の Item.parent のルールに従います。レイアウトマネージャーの内部に配置された要素は、そのレイアウトマネージャーの子となります。レイアウトマネージャーは、その子たちの x, y, width, height を自動的に設定します。

Loader を使用した動的な子要素のロード

Loader は、QMLファイルやコンポーネントを動的にロードし、その親として機能することができます。これは、アプリケーションの起動時間を短縮したり、条件に基づいて異なるUI要素を表示したりする際に有効です。

特徴:

  • リソースの効率化: すべてのUI要素を最初からメモリにロードする必要がない。
  • 条件付きロード: アプリケーションの状態に応じて表示するUIを切り替えることができる。
  • 遅延ロード: 必要な時にだけQMLコンポーネントをロードできる。

:

// main.qml
import QtQuick
import QtQuick.Controls

ApplicationWindow {
    width: 400
    height: 300
    visible: true
    title: "Loader Example"

    Rectangle {
        id: container
        width: 200
        height: 150
        color: "lightgray"
        anchors.centerIn: parent

        Loader {
            id: myLoader
            anchors.fill: parent
            // Loaderの親はcontainer
            // ロードされるQMLの親もmyLoaderとなる(デフォルトで)
        }
    }

    Button {
        text: "コンポーネントAをロード"
        y: container.y + container.height + 20
        anchors.left: container.left
        onClicked: {
            myLoader.source = "ComponentA.qml";
        }
    }

    Button {
        text: "コンポーネントBをロード"
        y: container.y + container.height + 20
        anchors.left: children[0].right // 最初のボタンの右に配置
        anchors.leftMargin: 10
        onClicked: {
            myLoader.source = "ComponentB.qml";
        }
    }
}
// ComponentA.qml
import QtQuick

Rectangle {
    width: 100
    height: 100
    color: "red"
    anchors.centerIn: parent // Loader (myLoader) の中央に配置される

    Text {
        anchors.centerIn: parent
        text: "コンポーネントA"
    }
}
// ComponentB.qml
import QtQuick

Rectangle {
    width: 120
    height: 80
    color: "blue"
    anchors.centerIn: parent // Loader (myLoader) の中央に配置される

    Text {
        anchors.centerIn: parent
        text: "コンポーネントB"
        color: "white"
    }
}

Item.parent との関連: Loader がロードしたQMLコンポーネント(例: ComponentA.qml のルートの Rectangle)は、デフォルトで Loader インスタンスの子となります。つまり、ロードされたコンポーネントの parent プロパティは myLoader を指します。

Repetear / ListView / GridView を使用したデータ駆動型の子要素

RepeaterListViewGridView は、データモデルに基づいて多数の子要素を生成し、それらを効率的に表示・管理するための強力なメカニズムです。

特徴:

  • 柔軟なカスタマイズ: delegate プロパティで各アイテムの見た目を自由に定義できる。
  • ビューの再利用: 大量のアイテムがある場合でも、表示されている部分だけをレンダリングすることでパフォーマンスを最適化する(ListView/GridView)。
  • データバインディング: データモデルの変更に自動的にUIが更新される。

:

import QtQuick
import QtQuick.Controls

ApplicationWindow {
    width: 300
    height: 400
    visible: true
    title: "Repeater Example"

    Column {
        anchors.fill: parent
        anchors.margins: 10
        spacing: 5

        Repeater {
            model: ["Apple", "Banana", "Cherry", "Date", "Elderberry"]

            delegate: Rectangle {
                width: 200
                height: 40
                color: "lightgray"
                border.color: "darkgray"
                border.width: 1

                Text {
                    anchors.centerIn: parent
                    text: modelData // modelの各要素のデータ
                }

                MouseArea {
                    anchors.fill: parent
                    onClicked: {
                        console.log("クリックされたアイテム:", modelData);
                        // このdelegateの親はRepeaterの内部のItem(Repeaterのビューポート)
                        // そのさらに親はこのColumn
                        console.log("私の親のID:", parent.id); // Repeaterが生成した内部のItemのID
                        console.log("私の親の親のID:", parent.parent.id); // このColumnのID
                    }
                }
            }
        }
    }
}

Item.parent との関連: RepeaterListView などが生成する delegate のインスタンスは、それぞれのビューの内部的な Item の子となります。これらの Item は通常、直接アクセスする必要がない中間的なコンテナとして機能します。しかし、delegate 内から parent プロパティを参照すると、実際にその delegate インスタンスを保持している内部の Item を指します。そのさらに parent を参照していくと、RepeaterListView 自体、そしてその親へと遡ることができます。

QMLのItem.parentは、C++のQQuickItem::parentItem() (取得) や QQuickItem::setParentItem() (設定) に対応しています。これは、C++で動的にQQuickItemのインスタンスを作成し、それを既存のQMLツリー内の別のItemの子として追加したい場合に利用できます。

特徴:

  • 動的なオブジェクト生成と配置: プログラム的にUI要素を生成し、任意の場所に配置できる。
  • C++とQMLの連携: C++のロジックに基づいてQMLの視覚ツリーを操作する。

Item.parent との関連: これは Item.parent の直接的なC++ APIであり、QML側で parent: someId と記述するのと同じ効果を持ちます。