[英]JavaFX: Bidirectional Binding in FXML
我正在使用 JavaFX,并且正在研究数据绑定。 我发现我可以在 FXML 中定义单向绑定,如下所示:
<TextField fx:id="usernameTextField" text="${controller.userName}" GridPane.columnIndex="1" />
这意味着, usernameTextField 的文本正在“观察” controller.userName 属性。
但这会创建一种单向绑定。 如果 controller.userName 属性发生变化,我会在文本字段中看到更新的文本,该部分有效。 但是我不能再在文本字段中插入文本,因为我已经进行了单向绑定。
我能找到的所有关于此的帖子现在已经有四年多了,但我不知道 JavaFX 是否已更新以支持更复杂的绑定。
这样做的方法是:
<TextField fx:id="usernameTextField" text="#{controller.userName}"/>
但是此功能尚未启用(最后在 OpenJFX 13 上检查),使用它会导致FXMLLoader
抛出UnsupportedOperationException("This feature is not currently enabled.")
FXMLLoader
UnsupportedOperationException("This feature is not currently enabled.")
。
正如已经说过的,没有简单的方法可以从 FXML 进行双向绑定。 然而,它可以从 FXML 完成,但不能使用 FXML 本身,可以这么说。 这是我的发现。
<fx:script>
块第一种也是最明显的方法是使用<fx:script>
通过 JavaScript 进行任何需要的绑定。 例如,可以使用以下代码段进行双向绑定:
<?language javascript?>
<!-- ... -->
<TextField fx:id="aControl"/>
<fx:script>
javafx.beans.binding.Bindings.bindBidirectional(
controller.someProperty(),
aControl.textProperty()
);
</fx:script>
这里someProperty()
是一个名为some
的属性的控制器方法。
第二个选项是创建一个辅助类,然后在<fx:define>
块中使用它(使用上面的约定):
<?import u7n.examples.BidiBind?>
<!-- ... -->
<TextField fx:id="aControl"/>
<fx:define>
<BidiBind o1="$controller" p1="some" o2="$aControl" p2="text"/>
</fx:define>
这是此类的示例实现:
package u7n.examples;
import javafx.beans.binding.Bindings;
import javafx.beans.property.Property;
public class BidiBind {
private Object o1;
private String p1;
public Object getO1() { return o1; }
public void setO1(Object o1) { this.o1 = o1; bind(); }
public String getP1() { return p1; }
public void setP1(String p1) { this.p1 = p1; bind(); }
private Object o2;
private String p2;
public Object getO2() { return o2; }
public void setO2(Object o2) { this.o2 = o2; bind(); }
public String getP2() { return p2; }
public void setP2(String p2) { this.p2 = p2; bind(); }
private <T> void bind() {
if (o1 == null || p1 == null || o2 == null || p2 == null) return;
try {
@SuppressWarnings("unchecked")
Property<T> property1 = (Property<T>)o1.getClass().getMethod(p1 + "Property").invoke(o1);
@SuppressWarnings("unchecked")
Property<T> property2 = (Property<T>)o2.getClass().getMethod(p2 + "Property").invoke(o2);
Bindings.bindBidirectional(property1, property2);
}
catch (Exception e) {
e.printStackTrace();
}
o1 = o2 = null;
p1 = p2 = null;
}
}
它使用反射来访问属性,因为我还没有找到让 FXMLLoader 将属性而不是其值传递给 setter 的方法。
两种方式都不是理想的,但是可以从 FXML 完成双向绑定,尽管不是很方便。 当然,像
<TextField fx:id="aControl" text="#{controller.some}"/>
会更好,但唉。 此外,我不知道这两种建议的方法与 Scene Builder 的配合效果如何,因为我不使用它。
此代码完美运行:
<TextField fx:id="usernameTextField" text="${controller.userName}"/>
要操作,控制器必须包含一个 getter :
public String getUserName() { return "mystringvalue"; }
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.