qt - 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 之后,我真的很困惑,有人能解释一下它是如何工作的吗?
解决方案
绑定更像是元属性而不是实际值。一旦您从 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 生成一个新值。
我希望我能解释你可以理解的行为。
推荐阅读
- python - 如何在python中的列表中查找嵌套列表的位置
- javascript - mySQL/Node 错误消息:“忽略传递给连接的无效配置选项:用户名”
- flutter - 如何实现 Stream 以获取每个文档的子集合列表?-扑
- django - 将身份验证添加到 django rest 框架 openapi
- reactjs - ReactJs / Native with Socket - 最佳实践
- jmespath - 使用 JMESPath 进行不区分大小写的搜索
- python - 如何在 Pandas 数据框中创建一个包含与 groupby 相同值的新列?
- spring-batch - 如何将 Spring Batch(无 Spring Boot)与 Spring Cloud Data Flow Server 集成
- javascript - 为什么对象属性返回“未定义”?
- python - 读取 CSV 文件并提取特定数据