当前位置: 首页 > 知识库问答 >
问题:

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

韦棋
2023-03-14

我有一个很大的OvervableList

在这个控制器中,我做了3个独立的FilteredList

private final BooleanProperty keep;
private final BooleanProperty delete;

这3个过滤列表显示在3个不同的ListViews中。

我在newData列表中的每个项目旁边都有按钮,我可以在其中设置keepdeletetrue。这样做应该将该网站对象移动到保留列表或删除列表。但是,当我单击按钮时,列表视图没有适当更新。

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个答案

华涵意
2023-03-14

为什么要使用Boolean属性,有什么原因吗?因为你可以只看3张单子。

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

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

在此之后,一切都应该工作正常。

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。

吕德业
2023-03-14

要更新FilteredList,需要触发添加到观察列表中的侦听器。默认情况下,修改列表元素的属性不起作用。

如果使用提取器为应触发更新更改的元素属性创建列表,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]

返回包含多个可观察s的数组会触发更新,如果其中任何一个可观察s被修改。

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

 类似资料:
  • 我想使用JavaFX ListView控件显示一个人员列表(在POJOS中编码,包含一个name和surname属性)。我创建了ListView,并将persons列表添加为ObservableList。如果我在ObservableList中删除或添加一个新人,那么一切都可以正常工作,但是POJO中的更改不会触发ListView的更新。我必须从ObservableList中移除和添加修改后的POJ

  • 你好, 我有一个问题,使ListView更新“良好”。这是一个包含一堆播放列表项的播放列表。基本上,当项的样式或内容发生变化时,我希望它在ListView中发生变化。当前,我刷新了整个列表,我猜这是可行的,但它似乎是一个很差(不清楚)的解决方案对我来说(它闪烁)。有没有一种方法可以刷新/重绘一个特定的物品?我还没找到。 null

  • 我正在创建一个TableView来显示有关自定义对象列表(EntityEvents)的信息。 表视图必须有2列。显示相应EntityEvent名称的第一列。第二列将显示一个按钮。按钮文本依赖于EntityEvent的属性。如果属性为零,则为“创建”,否则为“编辑”。 我做得很好,只是当相应的EntityEvent对象更改时,我找不到更新TableView行的方法。 非常重要:我不能将EntityE

  • 我有课: 阅读了手册后,我明白了我们需要在FX线程中刷新UI。我已经使用了platform.runlater(),但是在流结束时UI变慢了。 为我糟糕的英语感到抱歉。

  • 当我想更新JavaFX中的时,出现了一个问题。 调试很混乱,因为我找不到异常的原因。我在网上搜索了一下,但没有找到对我有用的东西。希望有人能帮我解决这个问题。

  • 由于响应于单击Set Default按钮所做的更改是更改ListView的UserData(),而不更改支持的ObservableList,因此列表不能正确地指示新的默认值。 是否有方法强制ListView重新呈现其ListCells?Android用户在这个问题上提出了成千上万个问题,但JavaFX似乎并不快乐。我可能不得不对支持数组进行“无意义的更改”来强制重绘。 我看到这是为JavaFX2.