如何在QtQuick中对TextEdit的属性`text`进行绑定?

时间:2018-05-08 17:00:13

标签: qt qml qtquick2 qt-quick

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

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

假设1:

TextEdit的text是只写的,并且始终显示其text属性被分配/绑定的内容(如果存在)。

实验1

操作

运行QML

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

在TextEdit中键入任何内容

预期文字始终显示“foo”,无法修改。

实际文字随您输入的内容而变化。

结论假设1是错误的。

假设2:

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

实验2

操作

运行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显示internalTexttext最近更改的内容。

实验3

操作

运行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,点击按钮后,显示屏将重置为“bar”。

实际第一次点击时显示设置为“bar”,之后点击该按钮完全没有效果。

结论假设3是假的......什么...... ??

并......

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

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

1 个答案:

答案 0 :(得分:1)

绑定更像是元属性而不是实际值。一旦你想象它是如何在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)));

正如您所看到的,绑定基本上是:"为我分配当前值,每当您的值发生变化时,请将我的值更新为您的值#34;。但是因为"这个"仍然拥有它自己的文本副本,你可以通过调用this->setText("something")来修改它而不破坏绑定(或者用c ++术语 - 信号连接)

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

现在进行第3次实验,有点棘手。 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生成新值。

我希望我能解释一下你能理解的行为。