【发布时间】:2017-03-12 08:44:25
【问题描述】:
我想观察一些 java bean 类的某些字段的变化。
该字段为枚举类型。
要绑定字段和相应的 ui 控件,我将使用 PropertyChangeListener,如 here 所述
但似乎 javaFX 没有等效的枚举属性类型。类似javafx.beans.property.EnumProperty
我尝试改用StringProperty 和ObjectProperty,但它不起作用。
更新:添加了一个sscce
Observable.java
package sample;
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class Observable {
protected PropertyChangeSupport propertyChangeSupport = null;
public Observable() {}
public void setObservableObject (Observable observable) {
propertyChangeSupport = new PropertyChangeSupport(observable);
}
public void addPropertyChangeListener(PropertyChangeListener listener){
System.out.println("added PropertyChangeListener");
propertyChangeSupport.addPropertyChangeListener(listener);
}
}
Item.java
package sample;
public class Item extends Observable {
public enum State {
INIT, STARTED
}
private String name;
private State state = State.INIT;
public Item() {
super();
super.setObservableObject(this);
}
public Item(String name, State state) {
this();
setName(name);
setState(state);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public State getState() {
return state;
}
public void setState(State state) {
State oldState = this.state;
this.state = state;
System.out.println(String.format("%s: change state from %s to %s",name,oldState.name(),state));
propertyChangeSupport.firePropertyChange("state", oldState, state);
}
}
Main.java
package sample;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) throws Exception {
Parent root = FXMLLoader.load(getClass().getResource("sample.fxml"));
primaryStage.setTitle("Item View");
primaryStage.setScene(new Scene(root, 200, 100));
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
sample.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.CheckBox?>
<?import javafx.scene.control.ComboBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.AnchorPane?>
<AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="108.0" prefWidth="225.0" xmlns="http://javafx.com/javafx/8.0.60" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller">
<children>
<Label layoutX="14.0" layoutY="14.0" text="show item" />
<ComboBox fx:id="cbxItemsSelector" layoutX="14.0" layoutY="31.0" prefWidth="150.0" />
<Button fx:id="btnChangeState" layoutX="14.0" layoutY="65.0" mnemonicParsing="false" onAction="#changeItemState" prefHeight="25.0" prefWidth="85.0" text="change state" />
</children>
</AnchorPane>
Controller.java
package sample;
import javafx.beans.Observable;
import javafx.beans.property.adapter.JavaBeanObjectPropertyBuilder;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.ComboBox;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.util.Callback;
import java.util.ArrayList;
import java.util.List;
public class Controller {
@FXML
private ComboBox<Item> cbxItemsSelector;
private ObservableList<Item> items;
public void initialize() {
loadItems();
customizeSelectorCellView();
}
private void loadItems() {
List<Item> itemsList = new ArrayList<>();
itemsList.add(new Item("first item", Item.State.INIT));
itemsList.add(new Item("second item", Item.State.INIT));
items = FXCollections.observableList(itemsList, item -> {
try {
return new Observable[]{
new JavaBeanObjectPropertyBuilder().bean(item).name("state").build()
};
} catch (NoSuchMethodException e) {
e.printStackTrace();
return new Observable[]{};
}
});
cbxItemsSelector.setItems(items);
}
private void customizeSelectorCellView() {
cbxItemsSelector.setButtonCell(new ListCell<Item>() {
@Override
protected void updateItem(Item item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText("");
} else {
setText(item.getName());
}
}
});
cbxItemsSelector.setCellFactory(
new Callback<ListView<Item>, ListCell<Item>>() {
@Override
public ListCell<Item> call(ListView<Item> p) {
ListCell cell = new ListCell<Item>() {
@Override
protected void updateItem(Item item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setText("");
} else {
System.out.println(String.format("update %s",item.getName()));
setText(String.format("name: %s\n state: %s\n", item.getName(), item.getState().name()));
}
}
};
return cell;
}
}
);
}
@FXML
public void changeItemState() {
Item selectedItem = cbxItemsSelector.getSelectionModel().getSelectedItem();
if (selectedItem == null) return;
selectedItem.setState(Item.State.STARTED);
}
}
所以,当我现在运行它时,我会得到下一个输出:
first item: change state from INIT to INIT
second item: change state from INIT to INIT
added PropertyChangeListener
added PropertyChangeListener
update first item
update second item
update first item
update second item
update first item
update first item
update second item
first item: change state from INIT to STARTED
second item: change state from INIT to STARTED
Process finished with exit code 0
如您所见,更新项目在项目状态更改后不会被调用。
我使用:jdk中包含的jre 1.8.0_91-b15 x64
【问题讨论】:
-
对象属性将起作用。
-
哦。是的。我发现了问题。我用FxControls Validation 控制。由于某种原因,如果启用验证,它将无法工作
-
@James_D 嗯,实际上验证不是问题的原因。我把它删掉了,反正也看到了同样的问题。但是奇怪的事情发生了。昨天这个例子奏效了,我看到了更新的状态。今天它不起作用。我没有改变任何东西。我刚刚添加了一个示例。请看一下。你能重现这个问题吗?