Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/376.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
Java 更改源后,TreeTableView选择包含空值_Java_Javafx_Treetableview_Easybind - Fatal编程技术网

Java 更改源后,TreeTableView选择包含空值

Java 更改源后,TreeTableView选择包含空值,java,javafx,treetableview,easybind,Java,Javafx,Treetableview,Easybind,基本值列表由(更改的)谓词过滤。FilteredList映射到TreeItems,然后将此结果列表用作根TreeItems子项 在TreeTableView上进行选择后,谓词发生更改,访问所选项目会导致NullPointerException 在我看来,变更中包含的项目是null。在这个粗糙的概念中是否存在设计缺陷 对于类TreeView和ListView,这不会发生 我尝试使用以下映射生成MCVE: import java.io.IOException; import java.util.Ar

基本值列表由(更改的)谓词过滤。
FilteredList
映射到
TreeItem
s,然后将此结果列表用作根
TreeItem
s子项

TreeTableView
上进行选择后,谓词发生更改,访问所选项目会导致
NullPointerException

在我看来,变更中包含的项目是
null
。在这个粗糙的概念中是否存在设计缺陷

对于类
TreeView
ListView
,这不会发生

我尝试使用以下映射生成MCVE:

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;

import org.fxmisc.easybind.EasyBind;

import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.SelectionMode;
import javafx.scene.control.Spinner;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeTableColumn;
import javafx.scene.control.TreeTableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class App extends Application {

    // fields protect bound lists from GC
    private ObservableList<DataItem> itemizedDataPool;
    private FilteredList<Data> filteredDataPool;
    private ObservableList<Data> selectedData;

    static class Data {
        final int value;

        public Data(int value) {
            this.value = value;
        }
    }

    static class DataItem extends TreeItem<Data> {
        final Data data;

        public DataItem(Data data) {
            this.data = data;
        }
    }

    @Override
    public void start(Stage primaryStage) throws IOException {

        List<Data> dataPool = new ArrayList<Data>();
        for (int i = 1; i < 20; i++) {
            dataPool.add(new Data(i));
        }

        filteredDataPool = new FilteredList<>(FXCollections.observableArrayList(dataPool));

        TreeTableView<Data> listView = createTreeTableView();
        Spinner<?> lowerBoundSelector = createLowerBoundFilter();
        Label sumLabel = createSummarizingLabel(listView.getSelectionModel().getSelectedItems());

        Parent root = new VBox(listView, lowerBoundSelector, sumLabel);

        Scene scene = new Scene(root, 768, 480);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private TreeTableView<Data> createTreeTableView() {
        itemizedDataPool = EasyBind.map(filteredDataPool, DataItem::new);
        TreeItem<Data> itemRoot = new TreeItem<>();
        Bindings.bindContent(itemRoot.getChildren(), itemizedDataPool);

        TreeTableView<Data> listView = new TreeTableView<>(itemRoot);
        listView.setShowRoot(false);
        itemRoot.setExpanded(true);
        listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
        listView.getColumns().add(new TreeTableColumn<>("Data"));
        return listView;
    }

    private Label createSummarizingLabel(ObservableList<TreeItem<Data>> selectedItems) {
        Label sumLabel = new Label();
        selectedData = EasyBind.map(selectedItems, (TreeItem<Data> t) -> ((DataItem) t).data);
        selectedData.addListener(new InvalidationListener() {
            @Override
            public void invalidated(Observable observable) {
                int sum = 0;
                for (Data d : selectedData) {
                    sum += d.value;
                }
                sumLabel.setText("Sum: " + sum);
            }
        });
        return sumLabel;
    }

    private Spinner<Integer> createLowerBoundFilter() {
        Spinner<Integer> lowerBoundSelector = new Spinner<>(0, 20, 0, 1);
        lowerBoundSelector.valueProperty().addListener(new InvalidationListener() {
            @Override
            public void invalidated(Observable observable) {
                filteredDataPool.setPredicate(t -> t.value > lowerBoundSelector.getValue());
            }
        });
        return lowerBoundSelector;
    }

    public static void main(String[] args) {
        launch(args);
    }

}
import java.io.IOException;
导入java.util.ArrayList;
导入java.util.List;
导入org.fxmisc.easybind.easybind;
导入javafx.application.application;
导入javafx.beans.InvalizationListener;
导入javafx.beans.Observable;
导入javafx.beans.binding.Bindings;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.collections.transformation.FilteredList;
导入javafx.scene.Parent;
导入javafx.scene.scene;
导入javafx.scene.control.Label;
导入javafx.scene.control.SelectionMode;
导入javafx.scene.control.Spinner;
导入javafx.scene.control.TreeItem;
导入javafx.scene.control.TreeTableColumn;
导入javafx.scene.control.TreeTableView;
导入javafx.scene.layout.VBox;
导入javafx.stage.stage;
公共类应用程序扩展应用程序{
//字段保护绑定列表不受GC影响
私有可观察列表项化数据池;
私有过滤器列表过滤器数据库工具;
私人观察者选择的数据;
静态类数据{
最终整数值;
公共数据(int值){
这个值=值;
}
}
静态类DataItem扩展了TreeItem{
最终数据;
公共数据项(数据){
这个数据=数据;
}
}
@凌驾
公共无效开始(阶段primaryStage)引发IOException{
List dataPool=new ArrayList();
对于(int i=1;i<20;i++){
添加(新数据(i));
}
filteredDataPool=新的FilteredList(FXCollections.observableArrayList(数据池));
TreeTableView listView=createTreeTableView();
微调器lowerBoundSelector=createLowerBoundFilter();
Label-sumlab=createSummaringLabel(listView.getSelectionModel().getSelectedItems());
父根=新VBox(listView、lowerBoundSelector、sumLabel);
场景=新场景(root,768480);
初级阶段。场景(场景);
primaryStage.show();
}
私有TreeTableView createTreeTableView(){
itemizedDataPool=EasyBind.map(filteredDataPool,DataItem::new);
TreeItem itemRoot=新的TreeItem();
Bindings.bindContent(itemRoot.getChildren(),itemizedDataPool);
TreeTableView listView=新的TreeTableView(itemRoot);
listView.setShowRoot(false);
setExpanded(true);
listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
添加(新的TreeTableColumn(“数据”);
返回列表视图;
}
私有标签CreateSummaringLabel(ObservableList selectedItems){
Label SUMLABLE=新标签();
selectedData=EasyBind.map(selectedItems,(TreeItem t)->(DataItem)t.data);
selectedData.addListener(新的InvalizationListener(){
@凌驾
公共无效(可观察到){
整数和=0;
对于(数据d:选定数据){
总和+=d.值;
}
sumlab.setText(“Sum:+Sum”);
}
});
退货标签;
}
专用微调器createLowerBoundFilter(){
微调器下限选择器=新微调器(0,20,0,1);
lowerBoundSelector.valueProperty().addListener(新的InvalizationListener()){
@凌驾
公共无效(可观察到){
setPredicate(t->t.value>lowerBoundSelector.getValue());
}
});
返回下限选择器;
}
公共静态void main(字符串[]args){
发射(args);
}
}
问题
TreeTableView
使用
TreeTableViewArrayListSelectionModel
,它扩展了
MultipleSelectionModelBase
,后者使用
ReadOnlyUnbackedObservableList
,后者使用(并包含)
SelectionListIterator
,其方法
nextIndex
的实现已中断

谢谢你指出这一点。 他还提交了一份bug报告()

变通办法 在两者之间使用缓冲区可以为上述问题提供有效的解决方法。我尝试了几种方法<在选择无效和绑定时,code>setAll。bindContent不起作用。在这两种情况下,我都收到列表中的
null
值。简单的“解决方案”是简单地过滤掉
null
s。这导致下面的代码效率低下,但显然很有效

// [...]
TreeTableView<Data> listView = createTreeTableView();
selectionBuffer = FXCollections.observableArrayList();
listView.getSelectionModel().getSelectedItems().addListener(new InvalidationListener() {
    @Override
    public void invalidated(Observable observable) {
        selectionBuffer.clear();
        for (TreeItem<Data> t : listView.getSelectionModel().getSelectedItems()) {
            if (t != null) {
                selectionBuffer.add(t);
            }
        }
    }
});
// [...]
/[…]
TreeTableView listView=createTreeTableView();
selectionBuffer=FXCollections.observableArrayList();
listView.getSelectionModel().getSelectedItems().addListener(新的InvalizationListener()){
@凌驾
公共无效(可观察到){
selectionBuffer.clear();
对于(TreeItem t:listView.getSelectionModel().getSelectedItems()){
如果(t!=null){
选择缓冲区。添加(t);
}
}
}
});
// [...]

使用
selectionBuffer
而不是
listView.getSelectionModel().getSelectedItems()
现在应该可以补偿
nextIndex
中的实现问题了