gpt4 book ai didi

javafx-2 - 动态 JavaFX 绑定(bind)

转载 作者:行者123 更新时间:2023-12-03 05:07:38 27 4
gpt4 key购买 nike

我的应用程序必须处理动态绑定(bind)。我有一个 Java Bean 对象列表,其中有很多必须编辑的属性。有多种类型的对象,具有不同的属性。

我创建一个 TreeView 来列出对象。每次我在 TreeView 中选择一个对象时,我都会更新屏幕中的第二个容器,在其中动态创建绑定(bind)到当前对象属性的标签和文本字段。

我使用 JavaBeanStringProperty、JavaBeanIntegerProperty 和该系列的其他对象来创建与 Java Bean 交互的属性。效果很好。我将每个 JavaBeanProperty 对象链接到其相应 TextField 的 TextAttribute,这样我就可以在 UI 更改时更新 Bean,反之亦然。

问题是:每次我在 TreeView 中选择一个新的 Java Bean 时,之前动态创建的所有对象似乎仍然存在。当我第一次选择 Bean 并对其进行编辑时,它会起作用,但第二次,它就不起作用了。

我尝试创建一个已创建绑定(bind)的列表,以便在选择新 Bean 时可以取消绑定(bind)它们,但是这是不可能的,因为 StringProperties 和 IntegerProperties 不共享公共(public)接口(interface),因此我可以取消绑定(bind)它们。

有人知道如何处理这个问题吗?

示例:

Bean 及其属性:

  • Bean1:名称(字符串)、金额(整数)
  • Bean2:名称(字符串),类型(字符串)
  • Bean3:名称(字符串)、地址(字符串)

如果我选择 Bean1,我会清除容器,并将这些新对象添加到其中:

  • 一个代表名称的 TextField,一个与 Bean 交互的 JavaBeanStringProperty,并将其与文本字段的 TextProperty 双向绑定(bind)。
  • 一个表示金额的 TextField,一个与 Bean 交互的 JavaBeanIntegerProperty,并使用 NumberConverter 将其与文本字段的 TextProperty 双向绑定(bind)。

当我选择 Bean2 时,我清除容器,并将这些新对象添加到其中:

  • 一个代表名称的 TextField,一个与 Bean 交互的 JavaBeanStringProperty,并将其与文本字段的 TextProperty 双向绑定(bind)。
  • 一个表示类型的 TextField,一个与 Bean 交互的 JavaBeanStringProperty,并将其与文本字段的 TextProperty 双向绑定(bind)。

当我选择 Bean3 时,我清除容器,并将这些新对象添加到其中:

  • 一个代表名称的 TextField,一个与 Bean 交互的 JavaBeanStringProperty,并将其与文本字段的 TextProperty 双向绑定(bind)。
  • 一个代表地址的 TextField,一个与 Bean 交互的 JavaBeanStringProperty,并将其与文本字段的 TextProperty 双向绑定(bind)。

这是一个完整的代码示例:

import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.lang.ref.WeakReference;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.adapter.JavaBeanIntegerProperty;
import javafx.beans.property.adapter.JavaBeanIntegerPropertyBuilder;
import javafx.beans.property.adapter.JavaBeanStringProperty;
import javafx.beans.property.adapter.JavaBeanStringPropertyBuilder;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.TextField;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Pane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
import javafx.util.converter.NumberStringConverter;

public class Main extends Application {

//=============================================================================================
public abstract class Bean {
public abstract void createUI(Pane container);
}

//=============================================================================================
public class Bean1 extends Bean {
private String name;
private int amount;

private PropertyChangeSupport pcs = new PropertyChangeSupport(this);

public Bean1(String name, int amount) {
this.name = name;
this.amount = amount;
}

public String toString() { return name; }

public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
System.out.println("Bean 1 PCS has " + pcs.getPropertyChangeListeners().length + " listeners. 1 was possuibly added.");
}

public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
System.out.println("Bean 1 PCS has " + pcs.getPropertyChangeListeners().length + " listeners. 1 was possuibly removed.");
}

public String getName() { return name; }

public void setName(String name) {
String last = this.name;
this.name = name;
pcs.firePropertyChange("name", last, this.name);
System.out.println("Bean 1: name changed: " + last + " -> " + this.name);
}

public int getAmount() { return amount; }

public void setAmount(int amount) {
int last = this.amount;
this.amount = amount;
pcs.firePropertyChange("amount", last, this.amount);
System.out.println("Bean 1: amount changed: " + last + " -> " + this.amount);
}

public void createUI(Pane container) {
HBox nameContainer = new HBox();
Label nameLabel = new Label("name: ");
nameLabel.setPrefWidth(80);
TextField nameValue = new TextField();
nameValue.setPrefWidth(140);

try {
JavaBeanStringProperty wrapper = new JavaBeanStringPropertyBuilder().bean(this).name("name").build();
nameValue.textProperty().bindBidirectional(wrapper);
} catch (NoSuchMethodException e) {
e.printStackTrace();
System.out.println("Exception binding Bean 1 name property.");
}

nameContainer.getChildren().addAll(nameLabel, nameValue);

HBox amountContainer = new HBox();
Label amountLabel = new Label("amount: ");
amountLabel.setPrefWidth(80);
TextField amountValue = new TextField();
amountValue.setPrefWidth(140);

try {
JavaBeanIntegerProperty wrapper = new JavaBeanIntegerPropertyBuilder().bean(this).name("amount").build();
Bindings.bindBidirectional(amountValue.textProperty(), wrapper, new NumberStringConverter());
} catch (NoSuchMethodException e) {
e.printStackTrace();
System.out.println("Exception binding Bean 1 amount property.");
}

amountContainer.getChildren().addAll(amountLabel, amountValue);

container.getChildren().clear();
container.getChildren().addAll(nameContainer, amountContainer);
}
}

//=============================================================================================
public class Bean2 extends Bean {
private String name;
private String type;

private PropertyChangeSupport pcs = new PropertyChangeSupport(this);

public Bean2(String name, String type) {
this.name = name;
this.type = type;
}

public String toString() { return name; }

public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
System.out.println("Bean 2 PCS has " + pcs.getPropertyChangeListeners().length + " listeners. 1 was possuibly added.");
}

public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
System.out.println("Bean 2 PCS has " + pcs.getPropertyChangeListeners().length + " listeners. 1 was possuibly removed.");
}

public String getName() { return name; }

public void setName(String name) {
String last = this.name;
this.name = name;
pcs.firePropertyChange("name", last, this.name);
System.out.println("Bean 2: name changed: " + last + " -> " + this.name);
}

public String getType() { return type; }

public void setType(String type) {
String last = this.type;
this.type = type;
pcs.firePropertyChange("type", last, this.type);
System.out.println("Bean 2: type changed: " + last + " -> " + this.type);
}

public void createUI(Pane container) {
HBox nameContainer = new HBox();
Label nameLabel = new Label("name: ");
nameLabel.setPrefWidth(80);
TextField nameValue = new TextField();
nameValue.setPrefWidth(140);

try {
JavaBeanStringProperty wrapper = new JavaBeanStringPropertyBuilder().bean(this).name("name").build();
nameValue.textProperty().bindBidirectional(wrapper);
} catch (NoSuchMethodException e) {
e.printStackTrace();
System.out.println("Exception binding Bean 2 name property.");
}

nameContainer.getChildren().addAll(nameLabel, nameValue);

HBox typeContainer = new HBox();
Label typeLabel = new Label("type: ");
typeLabel.setPrefWidth(80);
TextField typeValue = new TextField();
typeValue.setPrefWidth(140);

try {
JavaBeanStringProperty wrapper = new JavaBeanStringPropertyBuilder().bean(this).name("type").build();
typeValue.textProperty().bindBidirectional(wrapper);
} catch (NoSuchMethodException e) {
e.printStackTrace();
System.out.println("Exception binding Bean 2 type property.");
}

typeContainer.getChildren().addAll(typeLabel, typeValue);

container.getChildren().clear();
container.getChildren().addAll(nameContainer, typeContainer);
}
}

//=============================================================================================
public class Bean3 extends Bean {
private String name;
private String address;

private PropertyChangeSupport pcs = new PropertyChangeSupport(this);

public Bean3(String name, String address) {
this.name = name;
this.address = address;
}

public String toString() { return name; }

public void addPropertyChangeListener(PropertyChangeListener listener) {
pcs.addPropertyChangeListener(listener);
System.out.println("Bean 3 PCS has " + pcs.getPropertyChangeListeners().length + " listeners. 1 was possuibly added.");
}

public void removePropertyChangeListener(PropertyChangeListener listener) {
pcs.removePropertyChangeListener(listener);
System.out.println("Bean 3 PCS has " + pcs.getPropertyChangeListeners().length + " listeners. 1 was possuibly removed.");
}

public String getName() { return name; }

public void setName(String name) {
String last = this.name;
this.name = name;
pcs.firePropertyChange("name", last, this.name);
System.out.println("Bean 3: name changed: " + last + " -> " + this.name);
}

public String getAddress() { return address; }

public void setAddress(String address) {
String last = this.address;
this.address = address;
pcs.firePropertyChange("type", last, this.address);
System.out.println("Bean 3: address changed: " + last + " -> " + this.address);
}

public void createUI(Pane container) {
HBox nameContainer = new HBox();
Label nameLabel = new Label("name: ");
nameLabel.setPrefWidth(80);
TextField nameValue = new TextField();
nameValue.setPrefWidth(140);

try {
JavaBeanStringProperty wrapper = new JavaBeanStringPropertyBuilder().bean(this).name("name").build();
nameValue.textProperty().bindBidirectional(wrapper);
} catch (NoSuchMethodException e) {
e.printStackTrace();
System.out.println("Exception binding Bean 3 name property.");
}

nameContainer.getChildren().addAll(nameLabel, nameValue);

HBox addressContainer = new HBox();
Label addressLabel = new Label("type: ");
addressLabel.setPrefWidth(80);
TextField addressValue = new TextField();
addressValue.setPrefWidth(140);

try {
JavaBeanStringProperty wrapper = new JavaBeanStringPropertyBuilder().bean(this).name("address").build();
addressValue.textProperty().bindBidirectional(wrapper);
} catch (NoSuchMethodException e) {
e.printStackTrace();
System.out.println("Exception binding Bean 3 address property.");
}

addressContainer.getChildren().addAll(addressLabel, addressValue);

container.getChildren().clear();
container.getChildren().addAll(nameContainer, addressContainer);
}
}

//=============================================================================================
private class TreeItemRefresher implements PropertyChangeListener {
private String property;
private WeakReference<TreeItem<Bean>> treeItem;

TreeItemRefresher(String property, TreeItem<Bean> treeItem) {
this.property = property;
this.treeItem = new WeakReference<>(treeItem);
}

@Override
public void propertyChange(PropertyChangeEvent evt) {
if (property.equals(evt.getPropertyName())) {
// Workaround to repaint the tree item when its value object changes.
TreeItem<Bean> item = treeItem.get();
if (item != null) {
item.setExpanded(false);
item.setExpanded(true);
}
}
}
}

//=============================================================================================
private TreeView<Bean> treeView = new TreeView<>();
private VBox container = new VBox();

//=============================================================================================
@SuppressWarnings("unchecked")
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("Dynamic Bindings tests.");

HBox mainContainer = new HBox();

container.setPadding(new Insets(10));

// Creating beans.
Bean1 bean1 = new Bean1("Bean 1", 10);
Bean2 bean2 = new Bean2("Bean 2", "Type O");
Bean3 bean3 = new Bean3("Bean 3", "10, Central Park Av.");

// Creating TreeView
treeView.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
treeView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TreeItem<Bean>>() {
@Override
public void changed(ObservableValue<? extends TreeItem<Bean>> arg0, TreeItem<Bean> oldValue, TreeItem<Bean> newValue) {
Bean newItem = newValue.getValue();
newItem.createUI(container);
}
});

TreeItem<Bean> bean1item = new TreeItem<Bean>(bean1);
bean1.addPropertyChangeListener(new TreeItemRefresher("name", bean1item));

TreeItem<Bean> bean2item = new TreeItem<Bean>(bean2);
bean2.addPropertyChangeListener(new TreeItemRefresher("name", bean2item));

TreeItem<Bean> bean3item = new TreeItem<Bean>(bean3);
bean3.addPropertyChangeListener(new TreeItemRefresher("name", bean3item));

bean1item.setExpanded(true);
treeView.setRoot(bean1item);
bean1item.getChildren().addAll(bean2item, bean3item);

mainContainer.getChildren().addAll(treeView, container);

Scene scene = new Scene(mainContainer, 500, 300, Color.WHITE);
primaryStage.setScene(scene);
primaryStage.show();
}

//=============================================================================================
public Main() {
}

//=============================================================================================
public static void main(String[] args) {
launch(Main.class, args);
}

}

请注意,有时对字段的更改处理不完美。另请注意,当您更改所选 Bean 时,PropertyChangeListener 的数量始终会增加。我知道为什么会发生这种情况,但我真的不知道如何处理。

有更好的方法吗?请注意,我无法更改 Bean 对象。他们不在我的控制之下。

非常感谢。

最佳答案

您尝试过使用 JFXtras BeanPathAdaptor 吗?它是一个很棒的基于 POJOS 的动态绑定(bind)库。

你只需要使用

beanPathAdaptor.setBean(myNewBean);

当你想改变你的 bean 时!

这是一个链接: http://ugate.wordpress.com/2012/07/30/javafx-programmatic-pojo-expression-bindings-part-iii/

编辑

我看到的另一种方法是在 JavaFX 中定义 3 个自定义组件,每种类型一个。在其中,您可以定义与 bean 的完整绑定(bind),并将 View 绑定(bind)到您的 bean,并添加一个输入方法,例如“setBean1(Bean1 bean)”

然后,在选择时实例化该组件,显示它并使用“setBean1(...)”设置其内容。您可以对其他类型执行相同的操作。当然现在所有的绑定(bind)都是静态的,但是组件的创建和使用是动态的,它是面向组件的并且是高耦合的( View 模型)。

为了优化它,你可以将所有已经创建的组件保留在内存中,然后再次使用它们,以防止再次支付 View 的实例化费用,最好的方法应该是在不使用时将它们设置为visible==false如果您愿意,您甚至可以在初始化时对组件的所有可能情况进行热切实例化。

关于javafx-2 - 动态 JavaFX 绑定(bind),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22916835/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com