如何在JavaFX中动态更新ListView单元?

时间:2018-12-11 07:49:52

标签: java listview javafx

我有一个很大的OvervableList<Website>,可以通过调用mainApp.getWebsitData()获得。

在此控制器中,基于FilteredList<Websites>的2个布尔属性,我分别制作了3个keepDatadeleteDatanewDataWebsite

private final BooleanProperty keep;
private final BooleanProperty delete;

这3个过滤的列表以3个不同的ListView显示。

我在newDatakeep为真的delete列表中的每个项目旁边都有按钮。这样做应将网站对象移至保留列表或删除列表。但是,当我单击按钮时,列表视图无法正确更新。

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);

    }



}

关于如何动态更新列表的任何想法?

2 个答案:

答案 0 :(得分:2)

要更新FilteredList,需要触发添加到ObservableList的侦听器。默认情况下,修改列表元素的属性不会成功。

如果您使用提取器创建应触发更新更改的元素属性列表,则FilteredList也会更新。

示例

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);

输出

[3]
[3, 6]
[3, 6, 7]
[6, 7]

如果修改了Observable个数组,则返回包含多个Observable的数组会触发更新。

如果keepdelete实际上是与项目类型相关的属性,或者您只是添加了这些属性以将列表划分为3个FilteredList,我建议仔细检查。包含该项的数据库表中是否会包含这些值的列?如果必须将项目保存到文件中,可以将它们保存到输出文件中吗?
如果这些问题的答案是“否” ,则应使用3个单独的ObservableList。将项目从一个列表移动到另一个列表要比处理2个属性并根据这些属性过滤列表要复杂得多。

答案 1 :(得分:1)

为什么要为此使用BooleanProperty,有什么原因吗? 因为您可以只使用3 List。

您可以使用2个选项,可以为列表视图创建上下文菜单或它旁边的按钮,我是上下文菜单的粉丝。

在FXML中,您可以指定setOnAction()-Method,该方法可用于将选择模型从一个节点转移到您的保留或删除列表之一。

此后,一切都会正常运行。

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());
}

在此示例中,为按钮或上下文菜单指定了deleteSetOnActionMethod。