Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/309.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
添加列表项时不刷新JavaFX TableView行_Java_Javafx_Javafx 8 - Fatal编程技术网

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

添加列表项时不刷新JavaFX TableView行,java,javafx,javafx-8,Java,Javafx,Javafx 8,我有两个控制器,一个显示部件列表的主屏幕和一个打开第二个控制器窗口以添加新部件的按钮 当我添加一个部件时,它会很好地添加到arraylist中,但tableview不会更新。我在顶部有一个搜索字段,如果我按下按钮,它会显示新项目,但我尝试过的任何操作都不会使表刷新,并在添加新项目时显示新项目 这是主控制器 @Override public void initialize(URL url, ResourceBundle rb) { if (firstLoad) { inve

我有两个控制器,一个显示部件列表的主屏幕和一个打开第二个控制器窗口以添加新部件的按钮

当我添加一个部件时,它会很好地添加到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()));

}
阶段关闭后,主屏幕似乎根本没有更新,parts表视图中仍然包含3个部分

如果我将搜索文本字段留空并点击搜索按钮,第四部分将显示

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

您的代码有几处错误。最相关的是使用
FXCollections.observearraylist(Collection)
。此方法的Javadoc声明:

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

换句话说,它
集合
复制到一个新的
可观察列表
,该列表由
数组列表
支持。对原始
集合
的任何更新都不会添加到
可观察列表
。如果希望传递的
列表
作为支持
列表
的话,应该使用
FXCollections.observableList(List)

FXCollections.observableList(列表)
(我的重点):

构造由指定列表支持的ObservableList。ObservableList实例上的变异操作将报告给在该实例上注册的观察者。 请注意,直接对基础列表进行的突变操作不会报告给任何包装该列表的观察者。

这个Javadoc暗示了第二个问题。除非您在没有发布的代码中做了不同的操作,否则您会将元素添加到
ArrayList
字段(名为
allParts)
。因此,
ObservableList
从未意识到任何更改,因此不会触发任何更改事件。更改事件的触发在
可观察列表中进行编码。如果您希望收到更改通知,则必须仅通过包装
ArrayList
ObservableList
访问列表

在这种情况下,如果不是因为您也将
可观察列表
包装在
过滤器列表
中,您的代码仍然可以工作(当您调用
tableView.refresh()
)。
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);
    }

}
考虑到所有这些因素,修复代码的最简单方法是将
allParts
设置为
observeList
。否则,您必须注意仅使用围绕
ArrayList
创建的
ObservableList


编辑

您还提到,“如果我将搜索文本字段留空并点击搜索按钮,第四部分将显示”。我想解决这个问题。以下是您的代码,解释了当您点击搜索时,新的
零件
出现在
表格视图
中的原因:

/*
 * 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);
在创建
可观察列表之前添加
部分
。同样,
FXCollections.observearraylist(Collection)
拍摄
集合的快照,当在此处调用该方法时,该集合包含新的
部分
。如果要将代码翻转到:

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

然后
表视图
属性将不包含新的
部分
。但是,
库存
中的
所有部分
数组列表

好吧,我理解为什么搜索条目可以工作,因为它正在复制,但我不理解为什么在更新数组列表时,表没有更新。这似乎是在控制器之间切换时所特有的。如果我添加到主控制器上的arraylist,那么它会更新得很好,请参见我对OP的编辑。@WebKill在您的编辑中,您正在添加新的
部分
,然后再创建
可观察列表
。这意味着当您将
阵列列表
复制到一个新的、独立的(从
阵列列表
可观察列表时,
部分
已经在
所有部分
中。如果您要翻转这两条语句,
observebleList
将不包含新的
部分
。好的,我今天早些时候尝试了您的建议(将inventory类中的所有部分设置为可观察列表),但它不起作用,然后我在休息片刻后再次尝试,效果很好,我想我以前忘记初始化了。忽略排序的内容,因为我认为这混淆了主题,我现在对可观察列表应该如何工作有了更好的理解,现在它工作得更好了。非常感谢。
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]
/*
 * 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);
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));