Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/385.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 具有不同单元格高度的listview_Java_Listview_Javafx - Fatal编程技术网

Java 具有不同单元格高度的listview

Java 具有不同单元格高度的listview,java,listview,javafx,Java,Listview,Javafx,我正在尝试创建一个列表视图,其中所选单元格具有不同的UI(分别具有不同的高度)。单元格在FXML中声明,并创建自定义控件(DisplayRowDefault和DisplayRowSelected)以加载相应的FXML文件 我还设置了一个单元工厂,在那里我可以管理单元的渲染,具体取决于是否选中该单元 listView.setCellFactory(lv -> new ListCell<>() { private DisplayRowSelected selecte

我正在尝试创建一个
列表视图
,其中所选单元格具有不同的UI(分别具有不同的高度)。单元格在
FXML
中声明,并创建自定义控件(
DisplayRowDefault
DisplayRowSelected
)以加载相应的
FXML
文件

我还设置了一个单元工厂,在那里我可以管理单元的渲染,具体取决于是否选中该单元

listView.setCellFactory(lv -> new ListCell<>() {
        private DisplayRowSelected selectedGraphics;
        private DisplayRowDefault defaultGraphics;

        {
            defaultGraphics = new DisplayRowDefault();
            selectedGraphics = new DisplayRowSelected();
        }

        @Override
        protected void updateItem(Item item, boolean empty) {
            super.updateItem(item, empty);

            if(empty || item == null) {
                setContentDisplay(ContentDisplay.TEXT_ONLY);
                setGraphic(null);
            }
            else {
                selectedGraphics.setIndex(getListView().getItems().indexOf(item));
                selectedGraphics.setItem(item);

                setGraphic(isSelected() ? selectedGraphics : defaultGraphics);
                setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            }
        }
    }
);
编辑:MCVE

public class Sample extends Application {
    private class SelectedCell extends VBox {
        public SelectedCell() {
            getChildren().add(new Label("---"));
            getChildren().add(new Label("Selected Cell"));
            getChildren().add(new Label("---"));
        }
    }

    private class DefaultCell extends VBox {
        public DefaultCell() {
            getChildren().add(new Label("Default Cell"));
        }
    }

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

    @Override
    public void start(Stage primaryStage) {
        List<String> items = List.of("Item A", "Item B", "Item C", "Item D");

        ListView<String> listView = new ListView<>();
        listView.getItems().setAll(items);

        listView.setCellFactory(lv -> new ListCell<>() {
            private SelectedCell selectedCell = new SelectedCell();
            private DefaultCell defaultCell = new DefaultCell();

            @Override
            protected void updateItem(String s, boolean b) {
                super.updateItem(s, b);

                if(s == null || b) {
                    setContentDisplay(ContentDisplay.TEXT_ONLY);
                    setGraphic(null);
                }
                else {
                    setGraphic(isSelected() ? selectedCell : defaultCell);
                    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                }
            }
        });

        Scene scene = new Scene(listView, 200, 500);

        primaryStage.setScene(scene);
        primaryStage.show();
    }
}
公共类示例扩展应用程序{
私有类SelectedCell扩展VBox{
公共选择单元格(){
getChildren().add(新标签(“--”);
getChildren().add(新标签(“选定单元格”);
getChildren().add(新标签(“--”);
}
}
私有类DefaultCell扩展VBox{
公共默认单元格(){
getChildren().add(新标签(“默认单元格”);
}
}
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
列表项=列表项(“A项”、“B项”、“C项”、“D项”);
ListView ListView=新建ListView();
listView.getItems().setAll(项);
setCellFactory(lv->new ListCell()){
private SelectedCell SelectedCell=新建SelectedCell();
私有DefaultCell DefaultCell=新的DefaultCell();
@凌驾
受保护的void updateItem(字符串s,布尔值b){
super.updateItem(s,b);
如果(s==null | | b){
setContentDisplay(仅限ContentDisplay.TEXT_);
设置图形(空);
}
否则{
setGraphic(isSelected()?selectedCell:defaultCell);
setContentDisplay(仅限ContentDisplay.GRAPHIC_);
}
}
});
场景=新场景(listView,200500);
初级阶段。场景(场景);
primaryStage.show();
}
}

虽然通过明确询问
prefHeight
(我在问题中提到)的解决方案有效,但这不是一个好的解决方案。原因是单个
节点的维度取决于放置它们的上下文。因此,不能总是确定
prefHeight

通过设计,
ListView
被设计为在编辑模式下,单元格使用不同的用户界面,更改模式会导致正确地重新计算单元格大小。因此,我选择在更改选择时开始/停止编辑当前单元格的方法

这是我找到的解决方案,它工作正常:

public class Sample extends Application {
    private class SelectedCell extends VBox {
        public SelectedCell() {
            getChildren().add(new Label("---"));
            getChildren().add(new Label("Selected Cell"));
            getChildren().add(new Label("---"));
        }
    }

    private class DefaultCell extends VBox {
        public DefaultCell() {
            getChildren().add(new Label("Default Cell"));
        }
    }

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

    @Override
    public void start(Stage primaryStage) {
        List<String> items = List.of("Item A", "Item B", "Item C", "Item D");

        ListView<String> listView = new ListView<>();
        listView.getItems().setAll(items);

        listView.setEditable(true);

        listView.setCellFactory(lv -> new ListCell<>() {
            private SelectedCell selectedCell = new SelectedCell();
            private DefaultCell defaultCell = new DefaultCell();

            {
                selectedProperty().addListener((observable, oldValue, newValue) -> {
                    if (oldValue != null && oldValue) {
                        cancelEdit();
                    }

                    if (newValue != null && newValue) {
                        startEdit();
                    }
                });
            }

            @Override
            public void startEdit() {
                super.startEdit();
                setGraphic(selectedCell);
            }

            @Override
            public void cancelEdit() {
                if(!isSelected()) {
                    super.cancelEdit();
                    setGraphic(defaultCell);
                }
            }

            @Override
            protected void updateItem(String s, boolean b) {
                super.updateItem(s, b);

                if(s == null || b) {
                    setContentDisplay(ContentDisplay.TEXT_ONLY);
                    setGraphic(null);
                }
                else {
                    setGraphic(isEditing() ? selectedCell : defaultCell);
                    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
                }
            }
        });

        Scene scene = new Scene(listView, 200, 500);

        primaryStage.setScene(scene);
        primaryStage.show();
    }
}
公共类示例扩展应用程序{
私有类SelectedCell扩展VBox{
公共选择单元格(){
getChildren().add(新标签(“--”);
getChildren().add(新标签(“选定单元格”);
getChildren().add(新标签(“--”);
}
}
私有类DefaultCell扩展VBox{
公共默认单元格(){
getChildren().add(新标签(“默认单元格”);
}
}
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公共无效开始(阶段primaryStage){
列表项=列表项(“A项”、“B项”、“C项”、“D项”);
ListView ListView=新建ListView();
listView.getItems().setAll(项);
listView.setEditable(true);
setCellFactory(lv->new ListCell()){
private SelectedCell SelectedCell=新建SelectedCell();
私有DefaultCell DefaultCell=新的DefaultCell();
{
selectedProperty().addListener((可观察、旧值、新值)->{
if(oldValue!=null&&oldValue){
取消编辑();
}
if(newValue!=null&&newValue){
startEdit();
}
});
}
@凌驾
公开作废已启动IT(){
super.startEdit();
setGraphic(selectedCell);
}
@凌驾
公共作废取消编辑(){
如果(!isSelected()){
super.cancelEdit();
设置图形(默认单元格);
}
}
@凌驾
受保护的void updateItem(字符串s,布尔值b){
super.updateItem(s,b);
如果(s==null | | b){
setContentDisplay(仅限ContentDisplay.TEXT_);
设置图形(空);
}
否则{
setGraphic(IsEdit()?selectedCell:defaultCell);
setContentDisplay(仅限ContentDisplay.GRAPHIC_);
}
}
});
场景=新场景(listView,200500);
初级阶段。场景(场景);
primaryStage.show();
}
}

如注释中所述,这可能是一个bug(或者不是—单元格有许多属性,它们之间的相互作用没有完全指定)。黑客的解决办法-这里:触发假编辑转换或手动设置高度-通常是需要的

侦听所选属性时的假编辑转换会破解此问题,这一事实表明我们需要在更改通知链中“更早”(比updateItem早)更新图形,即当所选属性发生更改时:

  • 要挂接的方法(而不是手动侦听)是
    updateSelected(布尔)
  • 根据需要覆盖并更改图形
代码片段:

@Override
public void updateSelected(boolean selected) {
    super.updateSelected(selected);
    setGraphic(selected ? selectedCell : defaultCell);
}



@Override
protected void updateItem(String s, boolean b) {
    super.updateItem(s, b);

    if(s == null || b) {
        setContentDisplay(ContentDisplay.TEXT_ONLY);
        setGraphic(null);
    }
    else {
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        setGraphic(isSelected() ? selectedCell : defaultCell);
    }
}

要覆盖单元格的updateSelected(boolean)方法并根据需要设置单元格的图形:

我没有仔细查看,但从表面上看,它可能会有所帮助。@kleopatra,readyhmm。。很好,你找到了一个解决办法:)不过,想知道
@Override
public void updateSelected(boolean selected) {
    super.updateSelected(selected);
    setGraphic(selected ? selectedCell : defaultCell);
}



@Override
protected void updateItem(String s, boolean b) {
    super.updateItem(s, b);

    if(s == null || b) {
        setContentDisplay(ContentDisplay.TEXT_ONLY);
        setGraphic(null);
    }
    else {
        setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        setGraphic(isSelected() ? selectedCell : defaultCell);
    }
}