首页 > 解决方案 > QtQuick 中 TextEdit 的属性 `text` 的绑定如何工作?

问题描述

我是 QML 的初学者,我正在尝试遵循 QtQuick 的标准组件的行为作为指导。

我想以 TextEdit 的工作方式实现用户输入组件。但现在它真的让我很困惑该text属性是如何实现的。

假设1:

TextEdittext是只写的,并且总是显示什么,如果它存在,它的text属性被分配/绑定到 .

实验一

手术

运行 QML

Window {
    visible: true
    property string foo: "foo"
    TextEdit { text: foo }
}

在 TextEdit 中输入任何内容

预期文本始终显示“foo”并且无法编辑。

实际文本随您键入的内容而变化。

结论假设 1 是错误的。

假设 2:

text属性设置为它在初始化时绑定的内容。一旦用户编辑它,它text就会被分配给一个新值,这会破坏绑定。

实验二

手术

运行 QML

Window {
    visible: true
    property string foo: "foo"
    TextEdit { id: t1; text: foo; x: 0; }
    TextEdit { id: t2; text: t1.text; x: 100 }
}

在 t2 中输入一些内容,然后在 t1 中输入一些内容

预计t2 编辑后,编辑 t1 将不再改变 t2 的显示。

实际t2 可以单独编辑。但是一旦再次编辑 t1,t2 的显示就会再次绑定到 t1。

结论假设 2 是错误的。

假设 3:

TextEdit 有类似的东西internalText代表用户输入的内容。并且 TextEdit 显示最新更改的任何一个internalText或任何一个。text

实验三

手术

运行 QML

Window {
    visible: true
    property string foo: "foo"
    TextEdit { id: t1; text: foo; x: 0; }
    Button { x: 100; onClick: foo = "bar" } // A custom button
}

在 t1 中输入“blablabla”

点击按钮

在 t1 中输入“blablabla”

点击按钮,点击按钮,点击按钮一千次

预期t1 可以编辑,并且在单击按钮时显示重置为“条形图”。

实际第一次单击时显示设置为“栏”,然后单击按钮完全没有效果。

结论假设 3 是错误的……什么……??

和 ...

在多次阅读QML Reference 之后,尤其是Property Binding部分,我不知道如何可以写入和读取这样的属性(也不像 Angular 的 2 路绑定)。我很困惑。

在做了实验 3 之后,我真的很困惑,有人能解释一下它是如何工作的吗?

标签: qtqmlqtquick2qt-quick

解决方案


绑定更像是元属性而不是实际值。一旦您从 c++ 端想象它是如何工作的,就很容易理解。

绑定是使用信号和槽实现的。简单的 QML 线

text: foo.text

作为示例将等效于以下 c++ 代码(简化):

// first: call the getter of text on foo, and the setter on this
this->setText(foo->text());
// second: connect the change signal of foo to this
connect(foo, SIGNAL(textChanged(QString)),
        this, SLOT(setText(QString)));

如您所见,绑定基本上是:“为我分配当前值,并且每当您的值更改时,将我的值更新为您的值”。但是由于“this”仍然有它自己的文本副本,您当然可以通过调用this->setText("something")而不破坏绑定(或用 c++ 术语 - 信号连接)来修改它

这也解释了第二个(和第一个)实验:每当您在 GUI 中更改 t2 的文本时,都会更新 t2 的内部文本。但是,由于绑定仍然存在,因此每次更改 t1 时,t1 都会发出textChanged信号,因此也会更新 t2。

现在对于第三个实验,它变得有点棘手。c++ 代码被大大简化,只解释发生了什么,而不是它实际上是如何工作的。对于第三种情况,我们必须看看 qml 的 javascript 端。更具体:如何从 javascript 创建绑定:

// the qml line
text: foo
// is eqivalent to the js
t1.text = Qt.binding(function(){return foo;})

所以你并没有真正为 赋值t1.text,而是一个“绑定对象”。(该Qt.binding函数做了一些魔术并返回这样一个对象)这在内部与上面的 c++ 代码相同,但有一个区别。像在按钮中所做的那样,为 分配新值后t1.text,旧绑定以及信号连接将被删除,因为您将绑定对象替换为新值。

因此,在按钮中的 JS 代码中,将绑定对象替换为值“bar”,从而将其销毁。从 GUI 编辑文本不会破坏绑定,因为只有内部值发生变化,实际上没有从 QML 为属性分配任何内容。

编辑:现在后续按钮单击不执行任何操作的原因是:按下按钮一次后,foo 设置为“bar”,这会触发textChanged信号并因此更改 t1。但是,下次您按下按钮并且 foo 再次设置为 bar 时,它什么也不做,因为它已经是“bar”。您不会通过将其设置为与现在相同的值来更改任何内容。想象一下这样的 setter 实现:

void setText(QString text) {
    if(this->text == text)
        return;
    this->text = text;
    emit textChanged(text);
}

如果您修改代码,例如这样:

Button { x: 100; onClick: foo = t1.text + "bar" }

它总是会工作并相应地更新 foo,因为这个表达式总是为 foo 生成一个新值。

我希望我能解释你可以理解的行为。


推荐阅读