如何在不使用 QML 函数的情况下根据其当前值转换 QQuickItem 的 x 或 y 属性

How to transform a QQuickItem's x or y property based on its current value without using a QML function

我使用的是Qt 5.9.3商业版。

场景
我有在我的代码的 Qt QML 部分中执行的逻辑。单击某个随机按钮。我想将 QML 矩形移动到另一个位置。另一个位置是根据矩形的当前位置计算的 (x, y) position

以下是我想做的事情:

代码:

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
            }
        }
    }
}

本题objective:
请注意,我想以声明方式进行计算。我可以轻松地创建一个 QML function 并声明一些全局属性,这当然很容易,但进行此计算并不是问题的重点。我的 objective 是学习如何以声明方式执行此操作。如何根据 QQuickItem::x 的当前值本身对 QQuickItem::x 应用计算。

如果你运行这个问题中的示例代码,你会看到my_rect_1只是不断地在两个位置之间来回交换,这不是逻辑的真正意图是什么。该逻辑的目的是通过某个因素不断增加 my_rect_1::xmy_rect_1::y,这会导致 my_rect_1 在您继续单击另一个矩形 [=] 时向右和向下移动20=].

其他问题
是当我点击 my_rect_2.

时,我在 运行 时不断收到以下 error
qrc:/main.qml:12:5: QML Rectangle: Binding loop detected for property "x"

我知道 QML 抱怨 my_rect_1 中 属性 x 的循环依赖。我怎样才能避免这种情况并实现一种声明性的方式来转换 xy?

我通过搜索找到的潜在解决方案
看起来 Translate QML Type 在我想实现的逻辑中很有用,但是如何实现呢?

如果不编写在外部单独执行此转换的 QML 函数,我如何实现此行为 my_rect_1

好吧,"declaratively" 将简单地涉及绑定,它们在本质上是相当多的函数,并具有在表达式中涉及的值发生变化时自动重新计算的额外好处。

这是一个简单的例子,它会在屏幕上显示一个红点,当点击 window 时,该点将移动到一个由该点的当前位置和点击位置得出的位置,把它放在两个坐标之间的假想线的中心:

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 属性实际上是多余的,没有它也可以实现同样的事情,但它需要手动操作点坐标,因此它的位置不会以纯粹的方式声明 "declarative way".这样它就绑定到 属性 值,并且无论哪个进程控制这些值,它都会继续跟随它们。

至于你的这部分代码:

  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
      }
  }

它是定义属性值的绑定表达式。如果您手动为 属性 赋值,它 会破坏 现有绑定。您所做的是为表达式中的 属性 分配一个值,该值应该自动执行 - 纯属胡说八道,这也解释了为什么它不能按预期工作。

适当的格式是:

  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      

等等...如您所见,使用此格式会删除绑定循环警告,现在您的行为与代码逻辑意图相匹配。