简体   繁体   English

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

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

I am using Qt 5.9.3 commercial version. 我正在使用Qt 5.9.3商业版本。

Scenario 脚本
I have logic to be executed in Qt QML part of the my code. 我有在我的代码的Qt QML部分执行的逻辑。 On click of some random button. 在单击某个随机按钮时。 I want to move a QML rectangle to another position. 我想将QML矩形移动到另一个位置。 The other position is a calculated (x, y) position based on current position of the rectangle. 另一个位置是基于矩形的当前位置计算出的(x, y) position

Following is sort of what I want to do: 以下是我想做的事情:

Code: 码:

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

The objective of this question: 这个问题的目的是:
Note that I want to do the calculation declaratively. 请注意,我想声明性地进行计算。 I can easily create a QML function and do this declaring some global properties which is of course easy but doing this calculation is not the point of the question. 我可以轻松地创建一个QML函数 ,并声明一些全局属性,这当然很容易,但是进行此计算并不是问题的重点。 My objective is to learn how to to do this declaratively. 我的目标是学习如何声明式地执行此操作。 How to apply a calculation to a QQuickItem::x based on the QQuickItem::x 's current value itself.. 如何基于QQuickItem::x的当前值本身将计算应用于QQuickItem::x

If you run the example code in this question , you will see that my_rect_1 just keeps swapping between 2 positions back and forth which is not what the logic really intends. 如果在此问题中运行示例代码 ,您将看到my_rect_1只是在2个位置之间来回交换,这并不是逻辑真正的意图。 The intention of the logic is to keep incrementing my_rect_1::x and my_rect_1::y by a certain factor which would cause my_rect_1 to get moved rightwards and downwards as you keeping clicking on the other rectangle that is my_rect_2 . 逻辑的目的是使my_rect_1::xmy_rect_1::y继续增加一定的系数,这将导致my_rect_1在您继续单击另一个矩形my_rect_2向右和向下移动。

Other issue 其他问题
is that I keep getting the following error at runtime when I click on my_rect_2 . 是当我单击my_rect_2时,在运行时不断出现以下错误

qrc:/main.qml:12:5: QML Rectangle: Binding loop detected for property "x"

I understand QML is complaining about the circular dependency of the property x in my_rect_1 . 我了解QML抱怨my_rect_1属性x的循环依赖关系。 How can I avoid this and achieve a declarative way of transforming x and y ? 我如何避免这种情况并实现声明性的转换xy

Potential solution I found from my searches 我从搜索中发现的潜在解决方案
Looks like Translate QML Type can be useful in the logic I want to implement but how? 看起来Translate QML Type可以在我要实现的逻辑中有用,但是如何?

How can I achieve this behaviour without writing a QML function which does this transformation separately outside my_rect_1 ? 如何在不编写QML函数的情况下实现此行为,该函数不在 my_rect_1 之外单独进行此转换

Well, "declaratively" would simply involve bindings, which are in their essence pretty much functions, with the added benefit of automatic reevaluation upon changes in the values involved in the expressions. 好吧,“声明式”将只涉及绑定,绑定本质上是很多功能,并具有对表达式中涉及的值的更改进行自动重新评估的额外好处。

Here is a trivial example that will show a red dot on screen, and when clicking on the window, the dot will move to a location that is derived by the dot's current location and the clicked location, putting it right in the center of the imaginary line between the two coordinates: 这是一个简单的示例,该示例将在屏幕上显示一个红色的点,并且在单击窗口时,该点将移动到一个由该点的当前位置和单击的位置派生的位置,并将其放在虚构的中心两个坐标之间的线:

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

Note that the xpos and ypos properties are practically redundand, and the same thing can be achieved without that, but it would involve manually manipulating the dot coordinates, thus its position will not be declared in a purely "declarative way". 请注意,xpos和ypos属性实际上是冗余的,没有该属性也可以实现,但是这将涉及手动操作点坐标,因此,其位置将不会以纯粹的“声明性方式”声明。 This way it is bound to the property values, and will keep on following them regardless of what process controls the values. 这样,它将绑定到属性值,并且将继续遵循属性值,而不管是由哪个过程控制值。

As for this part of your code: 至于这部分代码:

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

It is the binding expression that defines the property value. 绑定表达式定义了属性值。 If you assign a value to a property manually, it breaks the existing binding. 如果您手动为属性分配值,则会破坏现有绑定。 What you do is you assign a value to the property in the expression that is supposed to do that automatically - pure nonsense, which also explains why it doesn't work as expected. 您要做的是为表达式中的属性分配一个应该自动执行的值-纯粹的废话,这也解释了为什么它无法按预期工作。

The appropriate format would be: 适当的格式为:

  x: {
      if (some_boolean_flag) {
          return current_x + current_x/10
      }
      else {
          var default_x = parent.width/6
          return default_x
      }
  }

Which can actually be distilled down to: 实际上可以将其精简为:

  x: some_boolean_flag ? current_x + current_x/10 : parent.width/6      

and so on... And as you see, using this format removes the binding loop warnings and now you have behavior that matches the code logic intent. 依此类推...正如您所看到的,使用这种格式将删除绑定循环警告,现在您的行为与代码逻辑意图相匹配。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM