我后来创建了一个TableView,并为每个TableColumns注册了Properties。编辑内部数据反映在TableView中就好了。
然而,使用ListView,它是一个不同的故事。除非我关闭框架并再次打开它,否则不会立即显示更改。
我的ListView包含ActionSteps。请注意,我使用了Javafx bean属性。
package application.objects;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.function.IntPredicate;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class ActionStep {
private StringProperty actionStepID;
private ObjectProperty<LocalDate> dateSet, dateFinished;
private StringProperty stepName;
private IntegerProperty completion;
private ArrayList<StepComment> comments;
public ActionStep(String name) {
actionStepID = new SimpleStringProperty();
stepName = new SimpleStringProperty();
dateSet = new SimpleObjectProperty<LocalDate>();
dateFinished = new SimpleObjectProperty<LocalDate>();
completion = new SimpleIntegerProperty();
stepName.setValue(name);
}
public void setName(String name) {
stepName.setValue(name);
}
public String getName() {
return stepName.getValue();
}
public StringProperty stepNameProperty() {
return actionStepID;
}
public void setID(String id) {
actionStepID.setValue(id);
}
public String getID() {
return actionStepID.get();
}
public StringProperty actionStepIDProperty() {
return actionStepID;
}
public void setCompletion(int percent) {
if (percent < 0 || percent > 100)
return;
completion.set(percent);
}
public int getCompletion() {
return completion.get();
}
public IntegerProperty completionProperty() {
return completion;
}
public void setDateSet(LocalDate date) {
dateSet.set(date);
}
public LocalDate getDateSet() {
return dateSet.get();
}
public ObjectProperty<LocalDate> dateSetProperty() {
return dateSet;
}
public void setDateFinished(LocalDate date) {
dateFinished.set(date);
}
public LocalDate getDateFinished() {
return dateFinished.get();
}
public ObjectProperty<LocalDate> dateFinishedProperty() {
return dateFinished;
}
public String toString() {
return stepNameProperty().get();
}
}
我的ListView也使用ObservableList。
@FXML
private ListView<ActionStep> actionStepsListView;
private ObservableList<ActionStep> listOfSteps;
listOfSteps = FXCollections.observableArrayList();
actionStepsListView.setItems(listOfSteps);
if (plan != null) {
ArrayList<ActionStep> arrayOfSteps = plan.getStepsArrayList();
for (int i = 0; i < arrayOfSteps.size(); i++)
listOfSteps.add(arrayOfSteps.get(i));
} else
plan = new ActionPlan();
为什么对ObservableList所做的更改不会反映在ListView中?我注意到ListView调用每个对象的toString()来在ListView中显示它们的值,而不是将它绑定到它们的属性。
我做错了什么?我应该覆盖一家细胞工厂吗?
答案 0 :(得分:6)
请注意,您尝试使用ListView
中的单元格比使用TableView
中的单元格更复杂。在TableView
中,单元格中显示的对象发生了变化,因此单元格很容易观察到这一点。在ListView
中,您希望单元格注意属于单元格中显示的对象的属性何时更改;这是进一步删除的步骤,所以你必须做一些额外的编码(虽然不多,正如你所见)。
您可以创建一个自定义单元工厂来绑定到stepNameProperty()
,但这很棘手(您必须确保在updateItem()
方法中取消绑定/删除旧项目的侦听器)
但是,更简单的方法是使用定义了提取器的ObservableList
。
首先,修复您的方法名称:您发布的代码中存在一些奇怪的不匹配。 getX / setX / xProperty方法名称应该都正确匹配。即而不是
public void setName(String name) {
stepName.setValue(name);
}
public String getName() {
return stepName.getValue();
}
public StringProperty stepNameProperty() {
return actionStepID;
}
你应该
public final void setName(String name) {
stepName.setValue(name);
}
public final String getName() {
return stepName.getValue();
}
public StringProperty nameProperty() {
return stepName;
}
和其他属性访问器方法类似。 (显然,字段的名称可以是您喜欢的任何内容,因为它们是私密的。)Making the get/set methods final is good practice.
然后,create the list with an extractor。提取器是一个函数,它将列表中的每个元素映射到列表将观察到的Observable
数组。如果这些值发生变化,它将向列表的观察者发送列表更新。由于您的ActionStep
toString()
方法引用了nameProperty()
,我认为如果ListView
发生更改,您希望更新nameProperty()
。所以你想做
listOfSteps = FXCollections.observableArrayList(
actionStep -> new Observable[] { actionStep.nameProperty() } // the "extractor"
);
actionStepsListView.setItems(listOfSteps);
请注意,在早期版本的JavaFX 2.2中,ListView
未正确观察更新事件的列表;在Java 8发布之前不久就修复了这个问题(如果我没记错的话)。(因为你标记了JavaFX8这个问题,我假设你正在使用Java 8,所以你应该没问题。)
如果您不使用Java 8,则可以使用以下(等效但更详细)的代码:
listOfSteps = FXCollections.observableArrayList(
new Callback<ActionStep, Observable[]>() {
@Override
public Observable[] call(ActionStep actionStep) {
return new Observable[] { actionStep.nameProperty() } ;
}
});
actionStepListView.setItems(listOfSteps);
答案 1 :(得分:1)
以下是使用自定义对象制作listview的示例:
public class JavaFX_ListView extends Application {
class MyObject {
String day;
int number;
MyObject(String d, int n) {
day = d;
number = n;
}
String getDay() {
return day;
}
int getNumber() {
return number;
}
@Override
public String toString() {
return number + " " + day;
}
}
ObservableList<MyObject> myList;
// Create dummy list of MyObject
private void prepareMyList() {
myList = FXCollections.observableArrayList();
myList.add(new MyObject("Sunday", 50));
myList.add(new MyObject("Monday", 60));
myList.add(new MyObject("Tuesday", 20));
}
@Override
public void start(Stage primaryStage) {
primaryStage.setTitle("sample");
prepareMyList();
ListView<MyObject> listView = new ListView<>();
listView.setItems(myList);
Pane root = new Pane();
root.getChildren().add(listView);
primaryStage.setScene(new Scene(root, 300, 250));
primaryStage.show();
// testing
Timer timer = new Timer();
timer.schedule(new UpdateListTask(), 1000, 1000);
}
public static void main(String[] args) {
launch(args);
}
// testing
public class UpdateListTask extends TimerTask {
@Override
public void run() {
Platform.runLater(new Runnable() {
@Override
public void run() {
myList.add(new MyObject("sample", Calendar.getInstance()
.getTime().getSeconds()));
}
});
}
}
}