17

オブジェクトのグローバルな位置 (またはその祖先の 1 つとの相対位置) を追跡し、それを他のアイテムの位置にバインドしたいと考えています。

私は次のように使用することを考えてmapFromItemいました:

SomeObject {
  x: ancestor.mapFromItem(trackedObject, trackedObject.x, 0).x
  y: ancestor.mapFromItem(trackedObject, 0, trackedObject.y).y
}

このアプローチの問題は、mapFromItemが一度評価され、その引数の 1 つが更新されても更新されないことです。さらに、マッピングは、コードで追跡できないオフセットによって変更された新しい位置を返すことがあります (しかし、それは手元の問題ではありません)。

私の 2 番目のアイデアは、オフセットを再帰的に合計する関数を実装し、提供された祖先 ( のようなものcalculateOffsetFrom(ancestor)) で停止することによって、グローバル位置を計算することでした。onXChangedそれでもこれは単なる関数であり、祖先の位置が変更されたときに再評価されることはありません (その関数で、呼び出しをそれぞれのシグナルにバインドしない限り)これは汚い解決策のように思えます)。

最後に、追跡するオブジェクトにプロパティを追加してから、それらにバインドします。

TrackedObject {
  property real offsetX: x + parent.x + parent.parent.x + parent.parent.parent.x ...
  property real offsetY: y + parent.y + parent.parent.y + parent.parent.parent.y ...
}

SomeObject {
  x: trackedObject.globalX
  y: trackedObject.globalY
}

しかしまあ...ええ...これはまったくスケーリングせず、醜いものです。

この問題をよりクリーンな方法で解決する方法を知っている人はいますか?

編集: 私に関する限り、この場合はアンカーを使用できません。SomeObjectコンポーネントは、ある点から別の点へのベジェ曲線を描くカスタム コンポーネントです (2 つの を接続しますTrackedObjects)。そのためには、座標の違いが必要です。私が正しければ、アンカーはそれらの間の距離を計算する方法を提供しません。

4

5 に答える 5

11

これは難しい点ですが、私のプロジェクトの 1 つで使用したハックは次のとおりです。緑の四角形が移動したときだけでなく、黄色の四角形 (緑rect 親) 移動:

import QtQuick 2.0;

Rectangle {
    id: window;
    width: 800;
    height: 480;

    property bool globalBit : true;

    function updatePos (item_orig, item_dest, bit) {
        var pos_abs = window.mapFromItem (item_orig.parent, item_orig.x, item_orig.y);
        return window.mapToItem (item_dest.parent, pos_abs.x, pos_abs.y);
    }

    Rectangle {
        id: rectYellow;
        width: 400;
        height: 300;
        x: 300;
        y: 200;
        color: "yellow";

        onXChanged: { globalBit = !globalBit; }
        onYChanged: { globalBit = !globalBit; }

        MouseArea {
            drag {
                target: rectYellow;
                minimumX: 0;
                minimumY: 0;
                maximumX: (rectYellow.parent.width - rectYellow.width);
                maximumY: (rectYellow.parent.height - rectYellow.height);
            }
            anchors.fill: parent;
        }
        Rectangle {
            id: rectGreen;
            x: 100;
            y: 100;
            width: 50;
            height: 50;
            color: "green";

            MouseArea {
                drag {
                    target: rectGreen;
                    minimumX: 0;
                    minimumY: 0;
                    maximumX: (rectGreen.parent.width - rectGreen.width);
                    maximumY: (rectGreen.parent.height - rectGreen.height);
                }
                anchors.fill: parent;
            }
        }
    }
    Rectangle {
        id: rectBlue;
        x: pos.x + 50;
        y: pos.y + 50;
        width: 50;
        height: 50;
        color: "blue";

        property var pos : updatePos (rectGreen, rectBlue, globalBit);
    }
}

秘訣は、mapfromItem と mapToItem の両方を使用して、すべての座標を最初の共通の祖先に戻し、関数を強制的に再評価することです。計算関数に渡すグローバルブールフラグを配置し、それぞれを反転させます。マップ上の可動要素が移動するとき...どこにでも配置する必要はありません。移動でき、祖先アイテム内にあるアイテムの親だけに配置する必要があります。

したがって、機能し、あなたの位置は常に正しくなり、非常にスケーラブルで、多くのコードを追加しません.

于 2013-08-08T10:20:30.283 に答える
2

以下のソリューションは、親の 'x' または 'y' 値のいずれかが変更されるたびに、 qmlElementToTrack.onPropertyNameXChanged()およびqmlElementToTrack.onPropertyNameYChanged()イベントをトリガーします。

これは、各親のonXChanged()およびonYChanged()シグナルにアタッチすることによって行われます。これらの値のいずれかが変更されると、 qmlElementToTrack のすべての親をトラバースして、 propertyNameXまたはpropertyNameYの値を再計算します。

(「絶対」ではなく)「相対的」に配置するには、現在の !== qmlElementToStopAtを各 while() 条件に追加します。

ElementToTrack {
  id: qmlElementToTrack
  property real propertyNameX: 0
  property real propertyNameY: 0
}

setPositionChangedToParents(qmlElementToTrack);


/**
  Connect to each parent's 'onXChanged' and 'onYChanged' signals.
*/
setPositionChangedToParents = function(current) {
    while (current && current.parent) {
        current.onXChanged.connect(calculatePropertyNameX);
        current.onYChanged.connect(calculatePropertyNameY);
        current = current.parent;
    }
};


/**
  Disconnects the signals set to all parents.
*/
removePositionChangedFromParents = function(current) {
    while (current && current.parent) {
        current.onXChanged.disconnect(calculatePropertyNameX);
        current.onYChanged.disconnect(calculatePropertyNameY);
        current = current.parent;
    }
};


/**
  When any parent's 'x' changes, recalculate the 'x' value for the 'property name'.
*/
calculatePropertyNameX = function() {
    var calculatedX, current;

    calculatedX = 0;
    current = qmlElementToTrack;

    while (current && current.parent) {
        calculatedX += current.x;
        current = current.parent;
    }

    propertyNameX = calculatedX;
};


/**
  When any parent's 'y' changes, recalculate the 'y' value for the 'property name'.
*/
calculatePropertyNameY = function() {
    var calculatedY, current;

    calculatedY = 0;
    current = qmlElementToTrack;

    while (current && current.parent) {
        calculatedY += current.y;
        current = current.parent;
    }

    propertyNameY = calculatedY;
};

于 2015-04-09T18:05:56.267 に答える
1

これが役立つかどうかはわかりませんが、TheBootroo が言及した上記の黄色の四角形、青の四角形、および緑の四角形の問題については、以下のコードを使用して問題を解決しました。

import QtQuick 2.0;

Rectangle {
id: window;
width: 800;
height: 480;


Rectangle {
    id: rectYellow;
    width: 400;
    height: 300;
    x: 300;
    y: 200;
    color: "yellow";

    MouseArea {
        drag {
            target: rectYellow;
            minimumX: 0;
            minimumY: 0;
            maximumX: (rectYellow.parent.width - rectYellow.width);
            maximumY: (rectYellow.parent.height - rectYellow.height);
        }
        anchors.fill: parent;
    }
    Rectangle {
        id: rectGreen;
        x: 100;
        y: 100;
        width: 50;
        height: 50;
        color: "green";

        MouseArea {
            drag {
                target: rectGreen;
                minimumX: 0;
                minimumY: 0;
                maximumX: (rectGreen.parent.width - rectGreen.width);
                maximumY: (rectGreen.parent.height - rectGreen.height);
            }
            anchors.fill: parent;
        }
    }
}
Rectangle {
    id: rectBlue;
    //Need to acheive the below behvior(commented)
    //x: window.x+rectYellow.x+rectGreen.x+50
    //y: window.y + rectYellow.y +rectGreen.y+50
    width: 50;
    height: 50;
    color: "blue";

}
Component.onCompleted: {
    rectBlue.x =Qt.binding(
                function()
                {
                     //Returns window.x+rectYellow.x+rectGreen.x+rectGreen.width
                    var docRoot = null;
                    var x=rectGreen.x;
                    if(!docRoot)
                    {
                       docRoot = rectGreen.parent;
                       x+=docRoot.x;

                       while(docRoot.parent)
                       {
                           docRoot = docRoot.parent;
                           x+=docRoot.x
                       }
                    }
                    return x+rectGreen.width;
                }

                )
    rectBlue.y = Qt.binding(
                function()
                {
                    //Returns window.y+rectYellow.y+rectGreen.y+rectGreen.height
                    var docRoot = null;
                    var y=rectGreen.y
                    if(!docRoot)
                    {
                       docRoot = rectGreen.parent;
                       y+=docRoot.y;

                       while(docRoot.parent)
                       {
                           docRoot = docRoot.parent;
                           y+=docRoot.y
                       }
                    }
                    return y+rectGreen.height;
                }

                )
    }


}

アイデアは、緑の四角形とその視覚的な祖先の位置を計算することにより、緑の四角形に対する青の四角形の位置を計算することです。

このソリューションの背後にあるインスピレーションは -> http://developer.nokia.com/Community/Wiki/How_to_create_a_Context_Menu_with_QMLです

于 2013-08-12T02:57:30.127 に答える
0

コードを独自の ItemPositionTracker.qml ファイルに移動することで、@Shubhanga の回答を少し改善しようとしました。

import QtQuick 2.3

Item {
    id: root

    property Item trackedItem
    property Item movedItem

    Component.onCompleted: {
        movedItem.x =
                Qt.binding(
                    function()
                    {
                        if (trackedItem === null) return 0;

                        var docRoot = trackedItem;
                        var x = trackedItem.x;

                        while(docRoot.parent)
                        {
                            docRoot = docRoot.parent;
                            x += docRoot.x
                        }

                        return x;
                    }

                    )
        movedItem.y =
                Qt.binding(
                    function()
                    {
                        if (trackedItem === null) return 0;

                        var docRoot = trackedItem;
                        var y = trackedItem.y

                        while(docRoot.parent)
                        {
                            docRoot = docRoot.parent;
                            y += docRoot.y
                        }

                        return y;
                    }

                    )
    }
}

コードは、次のように任意の QML オブジェクトに追加できるようになりました。

ItemPositionTracker {
    trackedItem: rectGreen
    movedItem: rectBlue
}

これにより、rectBlue が rectGreen に追従します。

于 2014-10-09T11:48:55.930 に答える