问题描述
我创建了一个TableView中前阵子和注册属性到每个TableColumn来的。内部数据的编辑反映自己在TableView中回来就好了。
I created a TableView a while back and registered Properties to each of the TableColumns. Editing of the internal data reflected itself back in the TableView just fine.
通过一个ListView,但是,它是一个不同的故事。这些变化没有被立即显示,除非我关闭框架,然后再次打开它。
With a ListView, however, it is a different story. The changes are not being shown right away unless I close the frame and open it again.
我的ListView由ActionSteps的。请注意,我用JavaFX的豆属性。
My ListView consists of ActionSteps. Note that I used the Javafx beans properties.
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为好。
My ListView uses an ObservableList as well.
@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中不反映自己的变化?我注意到,呼吁每一个对象的toString()ListView控件在ListView中显示它们的值,而不是将其绑定到他们的属性。
How come changes made to the ObservableList do not reflect themselves in the ListView? I noticed that the ListView called upon every object's toString() to display their values in the ListView, rather than binding it to their Properties.
我是什么做错了吗?我应该重写电池厂还是什么?
What am I doing wrong? Am I supposed to override a cell factory or something?
推荐答案
请注意,你试图做一些与细胞中的更复杂的的ListView
比你与在的TableView
细胞。在的TableView
,在单元格中显示的对象正在发生变化,所以很容易为细胞观察此。在的ListView
,你想要的单元格时,属于在单元格中显示的对象属性来更改的通知;这是一个另外的步骤中除去,所以你必须做一些额外的编码(虽然并不多,因为你会看到)。
Note that you're trying to do something more complex with the cells in your ListView
than you were with the cells in the TableView
. In the TableView
, the objects displayed in the cells were changing, so it was easy for the cells to observe this. In the ListView
, you want the cells to notice when properties that belong to the objects displayed in the cells change; this is one further step removed, so you have to do a bit of extra coding (though not much, as you'll see).
您可以创建一个自定义单元格工厂绑定到 stepNameProperty()
,但它是棘手的(你必须确保解除绑定/移除旧的物品听众的updateItem()
法)。
You could create a custom cell factory to bind to the stepNameProperty()
, but it's tricky (you have to make sure to unbind/remove listeners from old items in the updateItem()
method).
更简单的方法,不过,这是不是有据可查的是使用 ObservableList
与定义的提取。
The easier way, though, which isn't well documented is to use an ObservableList
with an extractor defined.
首先,解决您的方法名:你在code你贴一些奇怪的不匹配。该的getX / setX的/ xProperty方法名称都应该匹配正确。即而不是
First, fix your method names: you have some weird mismatches in the code you posted. The getX/setX/xProperty method names should all match correctly. I.e. instead of
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;
}
和类似的其他属性访问方法。 (显然,字段的名称可以是任何你喜欢的,因为他们是私有的。)的
and similarly for the other property accessor methods. (Obviously, the names of the fields can be anything you like, as they're private.) Making the get/set methods final is good practice.
然后,创建具有提取名单。提取的是,在列表中的每个元素映射到的观测
秒的数组,该列表将观察的功能。如果这些值的变化,它会火列表更新到列表中的观察员。由于您的 ActionStep
的toString()
方法引用 nameProperty()
,我假设你想要的的ListView
更新,如果 nameProperty()
的变化。所以,你想要做的。
Then, create the list with an extractor. The extractor is a function that maps each element in the list to an array of Observable
s which the list will observe. If those values change, it will fire list updates to the list's observers. Since your ActionStep
's toString()
method references the nameProperty()
, I assume you want the ListView
to update if the nameProperty()
changes. So you want to do
listOfSteps = FXCollections.observableArrayList(
actionStep -> new Observable[] { actionStep.nameProperty() } // the "extractor"
);
actionStepsListView.setItems(listOfSteps);
请注意,在早期版本的JavaFX 2.2的的ListView
没有正确观察名单更新事件;这是固定的(如果我没记错)前不久的Java 8的释放(由于标签问题JavaFX8,我假设你使用的是Java 8,所以你要在这里很好。)
Note that in earlier versions of JavaFX 2.2 the ListView
did not properly observe the list for update events; this was fixed (if I remember correctly) shortly prior to the release of Java 8. (Since you tagged the question JavaFX8, I assume you're using Java 8 and so you should be fine here.)
如果您不使用Java 8,可以使用以下(折合但更详细)code:
If you are not using Java 8, you can use the following (equivalent but more verbose) code:
listOfSteps = FXCollections.observableArrayList(
new Callback<ActionStep, Observable[]>() {
@Override
public Observable[] call(ActionStep actionStep) {
return new Observable[] { actionStep.nameProperty() } ;
}
});
actionStepListView.setItems(listOfSteps);
这篇关于ListView控件不反映变化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!