![](/img/trans.png)
[英]ListView not reflecting the change for notifyDataSetChanged()
[英]ListView is not reflecting changes
我在前面創建了一個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中顯示它們的值,而不是將它綁定到它們的Properties。
我究竟做錯了什么? 我應該覆蓋一家細胞工廠嗎?
請注意,您嘗試使用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;
}
並且類似地用於其他屬性訪問器方法。 (顯然,字段的名稱可以是您喜歡的任何內容,因為它們是私有的。) 將get / set方法設為final是很好的做法。
然后, 使用提取器創建列表 。 提取器是一個函數,它將列表中的每個元素映射到列表將觀察的Observable
數組。 如果這些值發生變化,它將向列表的觀察者發送列表更新。 由於ActionStep
的toString()
方法引用了nameProperty()
,我假設您希望在nameProperty()
更改時更新ListView
。 所以你想做
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);
以下是使用自定義對象制作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()));
}
});
}
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.