[英]How to update ListView cells dynamically in JavaFX?
I have a large OvervableList<Website>
that is obtained from calling mainApp.getWebsitData()
. 我有一个很大的
OvervableList<Website>
,可以通过调用mainApp.getWebsitData()
。
In this controller, I make 3 separate FilteredList<Websites>
: keepData
, deleteData
and newData
based on 2 boolean properties of Website
: 在此控制器中,基于
Website
2个布尔属性,我制作了3个单独的FilteredList<Websites>
: keepData
, deleteData
和newData
:
private final BooleanProperty keep;
private final BooleanProperty delete;
Those 3 filtered lists are displayed in 3 different ListView
s. 这3个过滤的列表显示在3个不同的
ListView
。
I have buttons next to each item in the newData
list where I make either keep
or delete
true. 我在
newData
列表中的每个项目旁边都有按钮,在其中我可以keep
true或delete
true。 Doing so should move that website object to either the keep list or delete list. 这样做应将网站对象移至保留列表或删除列表。 However, when I click the button the list views are not updating appropriately.
但是,当我单击按钮时,列表视图未正确更新。
public class WebsiteOverviewController {
@FXML
private ListView<Website> deleteList;
@FXML
private ListView<Website> keepList;
@FXML
private ListView<Website> newList;
@FXML
private JFXButton scanButton;
@FXML
private JFXButton pauseButton;
@FXML
private StackPane stackPane;
private BooleanProperty isScanning = new SimpleBooleanProperty(false);
private MainApp mainApp;
private FilteredList<Website> keepData;
private FilteredList<Website> deleteData;
private FilteredList<Website> newData;
private AtomicBoolean paused = new AtomicBoolean(false);
private Thread thread;
public WebsiteOverviewController() {
}
@FXML
public void initialize() {
scanButton.setContentDisplay(ContentDisplay.RIGHT);
}
public void setMainApp(MainApp mainApp) {
this.mainApp = mainApp;
keepData = new FilteredList<>(mainApp.getWebsiteData(), p -> (!p.getDelete() && p.getKeep()));
deleteData = new FilteredList<>(mainApp.getWebsiteData(), p -> (p.getDelete() && !p.getKeep()));
newData = new FilteredList<>(mainApp.getWebsiteData(), p -> (!p.getKeep() && !p.getDelete()));
if (!deleteData.isEmpty()) {
deleteList.setItems(deleteData);
deleteList.setCellFactory(param -> new ListCell<Website>() {
@Override
protected void updateItem(Website item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
} else {
setText(item.getWebsite());
}
}
});
}
if (!keepData.isEmpty()) {
keepList.setItems(keepData);
keepList.setCellFactory(param -> new ListCell<Website>() {
@Override
protected void updateItem(Website item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
} else {
setText(item.getWebsite());
}
}
});
}
if (!newData.isEmpty()) {
newList.setItems(newData);
newList.setCellFactory(param -> new ListCell<Website>() {
@Override
protected void updateItem(Website item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
} else {
HBox hBox = new HBox();
hBox.setAlignment(Pos.CENTER);
JFXButton keepBtn = new JFXButton("Keep");
JFXButton deleteBtn = new JFXButton("Delete");
Label label = new Label(item.getWebsite());
label.setAlignment(Pos.CENTER);
hBox.getChildren().addAll(keepBtn, label, deleteBtn);
setGraphic(hBox);
keepBtn.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
System.out.println(item.getWebsite());
item.setKeep(true);
}
});
}
}
});
}
scanButton.visibleProperty().bind(isScanning.not());
pauseButton.visibleProperty().bind(isScanning);
}
@FXML
public void handleScanInbox() {
isScanning.set(true);
if (thread == null) {
thread = new Thread() {
public void run() {
mainApp.handleScanInbox(paused);
}
};
thread.setDaemon(true);
thread.start();
} else {
synchronized (paused) {
if (paused.get()) {
paused.set(false);
paused.notify();
}
}
}
}
@FXML
public void handlePauseScanInbox() {
paused.compareAndSet(false, true);
isScanning.set(false);
}
}
Any ideas on how to update the lists dynamically? 关于如何动态更新列表的任何想法?
For the FilteredList
to be updated, the listener added to the ObservableList
needs to be triggered. 为了更新
FilteredList
,需要触发添加到ObservableList
的侦听器。 Modifying a property of a list element won't do the trick by default. 默认情况下,修改列表元素的属性不会成功。
If you create the list using a extractor for element properties that should trigger update changes, the FilteredList
updates too. 如果使用提取器创建应触发更新更改的元素属性的列表,则
FilteredList
也会更新。
Example 例
public class Item {
private final int i;
private final BooleanProperty keep = new SimpleBooleanProperty();
public Item(int i) {
this.i = i;
}
@Override
public String toString() {
return Integer.toString(i);
}
public BooleanProperty keepProperty() {
return keep;
}
public boolean isKeep() {
return keep.get();
}
public void setKeep(boolean value) {
keep.set(value);
}
}
ObservableList<Item> data = FXCollections.observableArrayList(new Callback<Item, Observable[]>() {
@Override
public Observable[] call(Item param) {
return new Observable[] { param.keepProperty() };
}
});
for (int i = 0; i < 10; i++) {
data.add(new Item(i));
}
FilteredList<Item> filtered = new FilteredList<>(data, Item::isKeep);
filtered.addListener((Observable o) -> System.out.println(filtered));
data.get(3).setKeep(true);
data.get(6).setKeep(true);
data.get(7).setKeep(true);
data.get(3).setKeep(false);
Output 产量
[3]
[3, 6]
[3, 6, 7]
[6, 7]
Returning an array containing multiple Observable
s triggers an update, if any of those Observable
s is modified. 如果修改了其中的任何
Observable
,则返回包含多个Observable
的数组将触发更新。
I recommend double checking, if keep
and delete
are actually properties associated with the item type or if you simply added those properties to be able to partition your list into 3 FilteredList
s. 我建议仔细检查,如果
keep
和delete
实际上是与项目类型相关联的属性,或者只是添加了这些属性以将列表划分为3个FilteredList
。 Would a database table containing the item contain columns for those values? 包含该项的数据库表中是否会包含这些值的列? Would you save them to a output file, if you had to save the items to a file?
如果必须将项目保存到文件中,是否会将它们保存到输出文件中?
If the answer to these questions is "No" , you should use 3 seperate ObservableList
s. 如果对这些问题的回答为“否” ,则应使用3个单独的
ObservableList
。 Moving items from one list to another is less complicated than dealing with 2 properties and filtering the list based on those. 将项目从一个列表移动到另一个列表要比处理2个属性并根据这些属性过滤列表要复杂得多。
Why you use a BooleanProperty for this, is there any reason? 为什么为此使用BooleanProperty,有什么原因吗? Because you can just go with 3 List.
因为您可以只使用3 List。
You can go with 2 Options, you can make a Context Menu for the List View or a Button next to it, i am a fan of the Context Menu. 您可以使用2个选项,可以为列表视图创建一个上下文菜单,或者在其旁边创建一个按钮,我是上下文菜单的粉丝。
In FXML you can specify a setOnAction()-Method, this method can be used to transfer the Selection Model from one Node to one of your keep or delete Lists. 在FXML中,您可以指定setOnAction()-Method,此方法可用于将选择模型从一个Node传输到保留或删除列表之一。
After this everything should work fine. 在此之后,一切应该正常。
private ListView<String>list;
private ListView<String> deleteList;
@FXML
private final void deleteSetOnAction(ActionEvent event) {
deleteList.getItems().addAll(list.getSelectionModel().getSelectedItems());
list.getItems().removeAll(list.getSelectionModel().getSelectedItems());
}
The deleteSetOnActionMethod is specified for a button or Context Menu in this example. 在此示例中,为按钮或上下文菜单指定了deleteSetOnActionMethod。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.