我正在使用Qt 5.9.3商业版本。
场景
我有要在我的代码的 Qt QML 部分中执行的逻辑。单击某个随机按钮时。我想将 QML 矩形移动到另一个位置。另一个位置是根据矩形的当前位置计算出的(x, y) 位置
。
以下是我想做的事情:
代码:
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 800
height: 600
title: qsTr("Hello World")
property bool some_boolean_flag: false
Rectangle {
id: my_rect_1
color: "blue"
width: parent.width / 4
height: parent.height / 4
z:1
property real current_x
property real current_y
x: {
if (some_boolean_flag) {
current_x = current_x + current_x/10
return current_x
}
else {
var default_x = parent.width/6
current_x = default_x
return current_x
}
}
y: {
if (some_boolean_flag) {
current_y = current_y + current_y/10
return current_y
}
else {
var default_y = parent.height/6
current_y = default_y
return current_y
}
}
}
Rectangle {
id: my_rect_2
color: "yellow"
width: parent.width/5
height: parent.height/5
x: parent.width - parent.width/4
y: parent.height - parent.height/4
z:2
MouseArea {
anchors.fill: parent
onClicked: {
// swapping the boolean flag between true and false
some_boolean_flag = !some_boolean_flag
}
}
}
}
此问题的目标:
请注意,我想以声明方式进行计算。我可以轻松创建一个 QML function并声明一些全局属性,这当然很容易,但进行此计算不是问题的重点。我的目标是学习如何以声明方式执行此操作。如何根据 QQuickItem::x
本身的当前值对 QQuickItem::x
应用计算。
如果您运行此问题中的示例代码,您将看到 my_rect_1
只是不断地在 2 个位置之间来回交换,这并不是逻辑的真正意图。该逻辑的目的是按某个因子不断递增 my_rect_1::x
和 my_rect_1::y
,这会导致 my_rect_1
移动当您持续点击另一个矩形 my_rect_2
时,会向右和向下移动。
其他问题
问题是,当我点击 my_rect_2
时,我在运行时不断收到以下错误。
qrc:/main.qml:12:5: QML Rectangle: Binding loop detected for property "x"
我了解 QML
正在提示 my_rect_1
中属性 x
的循环依赖。如何避免这种情况并实现转换 x
和 y
的声明性方式?
我从搜索中找到的潜在解决方案
看起来像Translate QML Type在我想要实现的逻辑中可能有用,但是如何实现呢?
如何在不编写在外部单独执行此转换的 QML 函数的情况下实现此行为 my_rect_1
?
最佳答案
嗯,“声明式”只涉及绑定(bind),其本质上几乎是函数,并且具有在表达式中涉及的值发生变化时自动重新计算的额外好处。
这是一个简单的示例,它将在屏幕上显示一个红点,当单击窗口时,该点将移动到由该点的当前位置和单击位置得出的位置,将其放在正中央两个坐标之间的假想线:
ApplicationWindow {
id: main
width: 640
height: 480
visible: true
property real xpos: 10
property real ypos: 10
Rectangle {
id: rect
x: xpos
y: ypos
width: 10
height: 10
radius: 5
color: "red"
}
MouseArea {
anchors.fill: parent
onClicked: {
xpos = (xpos + mouseX) * .5
ypos = (ypos + mouseY) * .5
console.log(ypos)
}
}
}
请注意,xpos 和 ypos 属性实际上是冗余的,没有这些属性也可以实现相同的效果,但它会涉及手动操作点坐标,因此它的位置不会以纯粹的“声明方式”声明。这样,它就绑定(bind)到属性值,并且无论哪个进程控制这些值,都会继续遵循它们。
至于这部分代码:
x: {
if (some_boolean_flag) {
current_x = current_x + current_x/10
return current_x
}
else {
var default_x = parent.width/6
current_x = default_x
return current_x
}
}
它是定义属性值的绑定(bind)表达式。如果您手动为属性分配值,则会破坏现有绑定(bind)。您要做的就是为表达式中的属性分配一个值,该值应该自动执行 - 纯粹是废话,这也解释了为什么它不能按预期工作。
适当的格式是:
x: {
if (some_boolean_flag) {
return current_x + current_x/10
}
else {
var default_x = parent.width/6
return default_x
}
}
实际上可以归结为:
x: some_boolean_flag ? current_x + current_x/10 : parent.width/6
等等...正如您所看到的,使用此格式可以删除绑定(bind)循环警告,现在您的行为与代码逻辑意图相匹配。
关于javascript - 如何在不使用 QML 函数的情况下根据 QQuickItem 的当前值转换其 x 或 y 属性,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48963118/