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

添加列表项时JavaFX TableView行不刷新

欧阳何平
2023-03-14

当我添加一个部件时,它会添加到arraylist中,但是tableview不会更新。我在顶部有一个搜索字段,如果我按下按钮,它会显示新项,但我所尝试的任何东西都不会让表刷新并在添加新项时显示新项。

这是主控制器

@Override
public void initialize(URL url, ResourceBundle rb) {
    if (firstLoad) {
        inventory.addPart(new Part(1,"Widget",1.13,5,1,8));
        inventory.addPart(new Part(2,"Sprocket",2.88,5,1,8));
        inventory.addPart(new Part(3,"Gear",3.46,5,1,8));

        firstLoad = false;
    }

    colPartID.setCellValueFactory(new PropertyValueFactory<>("partID"));
    colPartName.setCellValueFactory(new PropertyValueFactory<>("name"));
    colPartInvLevel.setCellValueFactory(new PropertyValueFactory<>("inStock"));
    colPartPrice.setCellValueFactory(new PropertyValueFactory<>("price"));

    tblParts.setItems(FXCollections.observableArrayList(inventory.getAllParts()));

}

inventory类有一个零件的静态arraylist

private static ArrayList<Part> allParts = new ArrayList<>();
inv.addPart(new Part(1,"test",2,3.46));
stage.close();
        FilteredList<Part> filteredData = new FilteredList<>(FXCollections.observableArrayList(inventory.getAllParts()), p -> true);

        String newValue = txtPartSearch.getText();

        filteredData.setPredicate(part -> {
            if (newValue == null || newValue.isEmpty()) {
                return true;
            }

            String lowerCaseFilter = newValue.toLowerCase();
            if (part.getName().toLowerCase().contains(lowerCaseFilter)) {
                return true;
            }
            return Integer.toString(part.getPartID()).equals(lowerCaseFilter);
        });

        SortedList<Part> sortedData = new SortedList<>(filteredData);
        sortedData.comparatorProperty().bind(tblParts.comparatorProperty());
        tblParts.setItems(sortedData);

编辑:

如果所有工作都在主控制器内完成,所有工作都很好。例如,如果我删除上面的整个搜索代码,并将其替换为以下两行(按下后在主控制器上执行),那么主控制器上的表将立即更新以显示新项。

inventory.addPart(new Part(6,"Test",5.23,4,2,8));
tblParts.setItems(FXCollections.observableArrayList(inventory.getAllParts()));

共有1个答案

左丘曦
2023-03-14

您的代码有几个问题。最相关的是使用fxCollections.observablearrayList(Collection)。这个方法的Javadoc声明

创建一个新的可观察数组列表,并向其中添加集合col的内容。

换句话说,它将集合复制到由ArrayList支持的新的ObservableList中。对原始集合的任何更新都永远不会添加ObservableList中。如果希望传递的列表作为支持列表,则应该使用FxCollections.ObservableList(列表)

这个Javadoc暗示了第二个问题。除非您在没有发布的代码中做了不同的操作,否则似乎您将元素添加到ArrayList字段(名为AllParts)。因此,ObservableList从不知道任何更改,因此不会触发任何更改事件。更改事件的触发在ObservableList中编码。如果希望收到更改通知,则只能通过包装ArrayListObservableList访问该列表。

在本例中,如果不是因为您还将ObservableList包装在FilteredList中,那么您的代码仍然可以工作(当您调用tableView.refresh())。FilteredList创建支持ObservableList的“视图”。如果支持ObservableList从不触发任何更改,则FilteredList不会被通知任何更改,这意味着它永远不知道更新这个“视图”。这意味着当您向ArrayList添加元素时,这些新元素是“视图之外”的(如果您要替换“视图内”的元素,更改将是可见的)。

您可以通过以下代码看到此行为:

import java.util.*;
import javafx.collections.*;
import javafx.collections.transformation.*;

public class Main {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("Hello");
        list.add("World");

        ObservableList<String> obsList = FXCollections.observableList(list);
        FilteredList<String> filteredList = new FilteredList<>(obsList);

        System.out.println("INITIAL STATE");
        System.out.printf("\tList: %s%n", list);
        System.out.printf("\tFilteredList: %s%n", filteredList);

        list.add("Goodbye");
        list.add("World");

        System.out.println("AFTER ADDING ELEMENTS");
        System.out.printf("\tList: %s%n", list);
        System.out.printf("\tFilteredList: %s%n", filteredList);

        list.set(0, "Foo");
        list.set(1, "Bar");

        System.out.println("AFTER REPLACING ELEMENTS");
        System.out.printf("\tList: %s%n", list);
        System.out.printf("\tFilteredList: %s%n", filteredList);
    }

}
INITIAL STATE
        List: [Hello, World]
        FilteredList: [Hello, World]
AFTER ADDING ELEMENTS
        List: [Hello, World, Goodbye, World]
        FilteredList: [Hello, World]
AFTER REPLACING ELEMENTS
        List: [Foo, Bar, Goodbye, World]
        FilteredList: [Foo, Bar]

编辑

您还提到,“如果我将搜索文本字段留空并单击搜索按钮,第四部分将出现”。我想解决这个问题。下面是您的代码,并解释了当您单击搜索时,为什么新的部分会出现在tableView中:

/*
 * I extracted the FXCollections.observableArrayList(Collection) out of the FilteredList
 * constructor to more easily see what is going on.
 */

/* 
 * You create a **new** ObservableList using FXCollections.observableArrayList(Collection). This basically
 * creates a *snapshot* of the List returnd by getAllParts() as it currently is. At this point the 4th
 * Part is in that returned List. This means the newly created ObservableList will also contian the new
 * Part (since observableArrayList(Collection) copies the data). However, the *old* ObservableList that
 * was already set on the TableView *does not* contain that 4th Part.
 */
ObservableList<Part> parts = FXCollections.observableArrayList(inventory.getAllParts());

// You create a FilteredList that performs no filtering around "parts". Note
// here that a Predicate that always returns true is equivalent to passing null
// as the Predicate.
FilteredList<Part> filteredData = new FilteredList<>(parts, p -> true);

// Get the search criteria
String newValue = txtPartSearch.getText();

filteredData.setPredicate(part -> {
    if (newValue == null || newValue.isEmpty()) {
        return true; // don't filter if there is no search criteria
                     // since the newValue will be null or blank in this
                     // case no Parts are filtered
    }

    // filter based on lower-case names and search critiera
    String lowerCaseFilter = newValue.toLowerCase();
    if (part.getName().toLowerCase().contains(lowerCaseFilter)) {
        return true;
    }
    // else filter by ID
    return Integer.toString(part.getPartID()).equals(lowerCaseFilter);
});

// Wrap the FilteredList in a SortedList and bind the comparatorProperty to
// the comparatorProperty of the TableView (allows sorting by column).
SortedList<Part> sortedData = new SortedList<>(filteredData);
sortedData.comparatorProperty().bind(tblParts.comparatorProperty());

// Set the sortedData to the TableView
tblParts.setItems(sortedData);

因此,当您搜索时,会看到新的部分出现的根本原因是,每次搜索时都要创建一个新的ObservableList。这个新的ObservableList具有GetAllParts()列表的最新状态。另外,正如我在评论中提到的,您的编辑基本上是在做与您的排序代码相同的事情。既然你这样做了:

inventory.addPart(new Part(6,"Test",5.23,4,2,8));
tblParts.setItems(FXCollections.observableArrayList(inventory.getAllParts()));
tblParts.setItems(FXCollections.observableArrayList(inventory.getAllParts()));
inventory.addPart(new Part(6, "Test", 5.23, 4, 2, 8));
 类似资料:
  • 我有一个输入字段,它使用的是。下面的确实返回了我的列表 该列表以代码隐藏方式生成,如下所示 我的观点 但是当我运行代码时,我得到了以下错误 \n\nSCRIPT1004:预期; 下面是它返回的一些结果:$(函数(){var list=list[2103]; 注意:所有粗体的措辞都是我的清单失败的地方。 我试着做

  • 问题内容: 我想要一个脚本,每当我单击“提交”按钮时,该脚本就会将表单中的文本回显到div标签。 我能够立即执行此操作,但是我希望即使我提交另一个文本,文本也仍会显示在div中。我希望每个新提交的文本都创建一个列表。将其添加到上一个列表。 可能与数据库有关,但我想知道,每次单击提交时,我只会得到当前提交的文本。 这样的脚本的例子 我只想在每次单击提交时将条目添加到列表中。 问题答案: 我很高兴你玩

  • 我正在尝试添加选项到一个动态选择输入,依赖于在另一个选择下拉菜单中选择的值。 我已经设法在选择父级中的值时填充数据对象。所有的my触发器也会被执行,子select被禁用,它应该包含数据对象中的所有值,但是它没有填充任何选项。 JS(Coffeescript)代码段: 最后一节特别重要,因为这是JSON数据对象应转换为新选项的地方。下面是在一种情况下响应的对象(根据Firebug): 在本例中,儿童

  • 我的目标是从用户输入的“AM”-“PM”字符串格式打印包含24小时十进制格式的进入和退出时间的列表,如以下字符串数组:{6AM#8AM,11AM#1PM,7AM#8PM,7AM#8AM,10AM#12PM,12PM#4PM,1PM#4PM,8AM#9AM} 我在for循环中声明了各个列表,并在循环中为它们赋值,但从代码中得到了以下运行时异常:java。lang.IndexOutOfBoundsEx

  • 我理解不能使用枚举器对列表进行修改 即使小于,它是否总是true?(据我所知,在这种情况下,数组不会被重新分配,因此枚举器必须有效); 为什么返回它设置为的元素,即使枚举器已经无效?(我的意思是,如果数组被重新分配...); 重新分配是否保存了项目的原始顺序?我的意思是如果某个项目的索引为n,添加和项目后是否会有相同的索引?(MSDN说在列表末尾添加一个对象)如果是这样,则在常规的循环中运行列表并

  • 问题内容: 我正在做一个项目。它只是显示任务列表并向其中添加新任务。我有3个班级。一种用于添加,一种用于查看,一种用于保存所有信息(或者我认为)。 我的列表中已经有2个任务,它们显示正确。 问题是,当我 添加 新任务时,它不会在视图中显示。我尝试了许多可能的解决方案: 只需将项目添加到列表 创建一个新列表,其中包含旧列表中的项目并重建适配器; 使用沿着与附加()命令; 等等 这是我的代码,有点混乱