如何省略 "Binding loop detected for property" 警告?
How to omit the "Binding loop detected for property" warning?
我决定重写这道题。我试着把它说清楚和简短,但没有成功。
我想要实现的是一个我可以放在任何东西(Rectangle
、Image
等等)上并让它响应触摸手势的对象。不幸的是,我 运行 遇到了一个我无法解决的问题。我找不到帮助,所以我在这里试试。
这里很简单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 超出指定区域,我将它们移回
- 我再次收到信号 "x changed" 或 "y changed"
- 我收到有关循环的错误消息,因为我的函数导致其自身再次执行
所以我想问:有没有其他简单的方法可以防止对象飞出屏幕并且不会同时收到绑定循环错误?
我知道我可以用Timer
不时检查目标的x
和y
,然后把它们带回来。
我知道我可以更改动画的 easing
和 duration
,使其停在容器边界上,但看起来它已停止。
说真的。有没有简单的方法?
无效的事情:
- 在容器外检测到对象后停止动画(如果它移动得非常快,它将停止在屏幕外)
- 停止动画然后改变目标的
x
或y
感谢大家到目前为止对我的帮助。很高兴知道我并不孤单:)
我认为您的问题是您在 属性 更新处理程序 (onTargetXChanged()
).
这可能会被 QML 引擎识别为投标循环,就像您将 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 */
}
}
解决问题 myX
应该是 x
,
的别名
property alias myX: rectangle2.x
您遇到此问题是因为 myX
正在更改 x
的值并且 x
正在更改 myX
的值:一个循环。
解决方法就是使用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: {
// }
}
我决定重写这道题。我试着把它说清楚和简短,但没有成功。
我想要实现的是一个我可以放在任何东西(Rectangle
、Image
等等)上并让它响应触摸手势的对象。不幸的是,我 运行 遇到了一个我无法解决的问题。我找不到帮助,所以我在这里试试。
这里很简单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 超出指定区域,我将它们移回
- 我再次收到信号 "x changed" 或 "y changed"
- 我收到有关循环的错误消息,因为我的函数导致其自身再次执行
所以我想问:有没有其他简单的方法可以防止对象飞出屏幕并且不会同时收到绑定循环错误?
我知道我可以用Timer
不时检查目标的x
和y
,然后把它们带回来。
我知道我可以更改动画的 easing
和 duration
,使其停在容器边界上,但看起来它已停止。
说真的。有没有简单的方法?
无效的事情:
- 在容器外检测到对象后停止动画(如果它移动得非常快,它将停止在屏幕外)
- 停止动画然后改变目标的
x
或y
感谢大家到目前为止对我的帮助。很高兴知道我并不孤单:)
我认为您的问题是您在 属性 更新处理程序 (onTargetXChanged()
).
这可能会被 QML 引擎识别为投标循环,就像您将 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 */
}
}
解决问题 myX
应该是 x
,
property alias myX: rectangle2.x
您遇到此问题是因为 myX
正在更改 x
的值并且 x
正在更改 myX
的值:一个循环。
解决方法就是使用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: {
// }
}