Qt Quick 5.5如何省略"检测到属性的绑定循环"警告? (QML)

时间:2015-07-28 08:19:58

标签: qt qml qtquick2 qt5.5

我决定重写这个问题。我试图说清楚简短,但它没有成功。

我想要实现的是一个可以放在任何物体上的物体(RectangleImage等等)并让它响应触摸手势。不幸的是我遇到了一个我无法解决的问题。我无法找到帮助,所以我在这里试试。

这里很简单main.qml

import QtQuick 2.5
import QtQuick.Controls 1.3
import QtQuick.Window 2.2
import QtQuick.Dialogs 1.2

ApplicationWindow {
    title: qsTr("Touch surface test")
    width: 640
    height: 480
    visible: true


    Rectangle {
        width: 200
        height: 60
        color: "blue"

        MyTouchSurface {
            id: myTouchSurface
            anchors.fill: parent
        }
    }

}

这是MyTouchSurface.qml

import QtQuick 2.5

MultiPointTouchArea {
    id: myTouchSurface

    // this is object I want to respond to touch gestures
    property Item target: parent

    // this is object I want to keep target in. I won't let target get out of it
    property Item container: parent.parent

    property double targetX: target.x
    property double targetY: target.y
    property double centerX: target.width / 2
    property double centerY: target.height / 2
    property double lastTouchX
    property double lastTouchY
    property double lastXDrag
    property double lastYDrag

    // here I calculate received touches and move target
    onPressed: {
        lastTouchX = touchPoints[0].sceneX
        lastTouchY = touchPoints[0].sceneY
        if (slidingAnimation.running)
            slidingAnimation.stop()
    }
    onTouchUpdated: {
        if (touchPoints.length) {
            target.x += touchPoints[0].sceneX - lastTouchX
            target.y += touchPoints[0].sceneY - lastTouchY
            lastXDrag = touchPoints[0].sceneX - lastTouchX
            lastYDrag = touchPoints[0].sceneY - lastTouchY
            lastTouchX = touchPoints[0].sceneX
            lastTouchY = touchPoints[0].sceneY
        }
        else
            startSliding()
    }

    // when lifting fingers off screen I want to slide target across it's container
    function startSliding() {
        slidingAnimation.toX = target.x + lastXDrag * 10
        slidingAnimation.toY = target.y + lastYDrag * 10
        slidingAnimation.restart()
    }

    // This is animation responsible for sliding the target
    ParallelAnimation {
        id: slidingAnimation
        property double toX
        property double toY
        property int animationDuration: 250
        NumberAnimation {
            target: myTouchSurface.target
            property: "x"
            to: slidingAnimation.toX
            duration: slidingAnimation.animationDuration
            easing.type: Easing.OutQuad
        }
        NumberAnimation {
            target: myTouchSurface.target
            property: "y"
            to: slidingAnimation.toY
            duration: slidingAnimation.animationDuration
            easing.type: Easing.OutQuad
        }
    }

    // this is how I keep target object within container
    onTargetXChanged: {
        if (container != null) {
            if (target.x + centerX < 0)
                target.x = -centerX
            else if (target.x + centerX > container.width)
                target.x = container.width - centerX
        }
    }
    onTargetYChanged: {
        if (container != null) {
            if (target.y + centerY < 0)
                target.y = -centerY
            else if (target.y + centerY > container.height)
                target.y = container.height - centerY
        }
    }
}

我想在MyTouchSurface中拥有所有计算和函数,因此很容易应用于其他对象并在另一个项目中使用它。

我遇到的问题是我不知道如何阻止目标对象移出容器。好吧,这里的代码工作得非常好,但它也会产生非常难看的关于绑定循环的错误。

发生的事情是:

  • 我检查目标x和y时更改
  • 如果x或y超出指定区域,我将它们移回
  • 我收到信号&#34; x已更改&#34;或者&#34; y改变了#34;再次
  • 我收到有关循环的错误,因为我的函数导致自己再次执行

所以我在问:是否有其他简单的方法可以防止对象飞离屏幕并且不会同时收到绑定循环错误?

我知道我可以使用Timer不时检查目标xy,并将其带回来。

我知道我可以更改动画的easingduration,使其在容器边界上停止,但看起来已停止。

严重。有没有简单的方法?

那些不起作用的事情:

  • 在容器外部检测到对象后停止动画(如果它移动得非常快,它将停止在屏幕外)
  • 停止动画,然后更改目标xy

谢谢大家帮助我。很高兴知道我并不孤单:)

3 个答案:

答案 0 :(得分:2)

我认为您的问题是您在属性更新处理程序(targetX)内更新了target.xy(对于onTargetXChanged()而言)。

这可能被QML引擎选为biding循环,就像你从target.x更改onTargetXChanged()一样,信号onTargetXChanged()将再次触发,因为它已绑定到它在财产double targetX: target.x

您可以尝试这样的事情:

TouchArea {
  property Item target  //  target is the Image object being moved
  property double targetX: target.x
  property double targetY: target.y

  onTargetXChanged: {
    /* if object is out of specified area move x respectively */
    performPropertyUpdate(args)
  }
  onTargetYChanged: {
    /* if object is out of specified area move y respectively */
    performPropertyUpdate(args)
  }

  function performPropertyUpdate(args) {
    /* actual setting of target.x or target.y */
  }
}

答案 1 :(得分:2)

解决方案只需使用Connections

import QtQuick 2.5

MultiPointTouchArea {
    id: myTouchSurface

    // this is object I want to respond to touch gestures
    property Item target: parent

    // this is object I want to keep target in. I won't let target get out of it
    property Item container: parent.parent

    property double targetX: target.x
    property double targetY: target.y
    property double centerX: target.width / 2
    property double centerY: target.height / 2
    property double lastTouchX
    property double lastTouchY
    property double lastXDrag
    property double lastYDrag

    // here I calculate received touches and move target
    onPressed: {
        lastTouchX = touchPoints[0].sceneX
        lastTouchY = touchPoints[0].sceneY
        if (slidingAnimation.running)
            slidingAnimation.stop()
    }
    onTouchUpdated: {
        if (touchPoints.length) {
            target.x += touchPoints[0].sceneX - lastTouchX
            target.y += touchPoints[0].sceneY - lastTouchY
            lastXDrag = touchPoints[0].sceneX - lastTouchX
            lastYDrag = touchPoints[0].sceneY - lastTouchY
            lastTouchX = touchPoints[0].sceneX
            lastTouchY = touchPoints[0].sceneY
        }
        else
            startSliding()
    }

    // when lifting fingers off screen I want to slide target across it's container
    function startSliding() {
        slidingAnimation.toX = target.x + lastXDrag * 10
        slidingAnimation.toY = target.y + lastYDrag * 10
        slidingAnimation.restart()
    }

    // This is animation responsible for sliding the target
    ParallelAnimation {
        id: slidingAnimation
        property double toX
        property double toY
        property int animationDuration: 250
        NumberAnimation {
            target: myTouchSurface.target
            property: "x"
            to: slidingAnimation.toX
            duration: slidingAnimation.animationDuration
            easing.type: Easing.OutQuad
        }
        NumberAnimation {
            target: myTouchSurface.target
            property: "y"
            to: slidingAnimation.toY
            duration: slidingAnimation.animationDuration
            easing.type: Easing.OutQuad
        }
    }

    Connections{
        target:myTouchSurface.target
        onXChanged:{
            if (container != null) {
                if (target.x + centerX < 0)
                    target.x = -centerX
                else if (target.x + centerX > container.width)
                    target.x = container.width - centerX
            }
        }

        onYChanged:{
            if (container != null) {
                if (target.y + centerY < 0)
                    target.y = -centerY
                else if (target.y + centerY > container.height)
                    target.y = container.height - centerY
            }
        }
    }

    // this is how I keep target object within container
//    onTargetXChanged: {

//    }
//    onTargetYChanged: {

//    }
}

答案 2 :(得分:0)

要解决问题,myX应该是x

的别名
property alias myX: rectangle2.x

您遇到此问题导致myX正在更改x的值,而x正在更改myX的值:循环。