JavaFX 8自定义ListView单元格it';这是邪恶的

JavaFX 8自定义ListView单元格it';这是邪恶的,listview,javafx,javafx-8,Listview,Javafx,Javafx 8,我有自定义ListView单元格我有带两个控件的HBox: 带有名称字段的标签 它必须从对象的上下文生成 例如,我设置了类字段的ListView项数组、if field type Boolean i create复选框、if String i create TextField等 问题是:我只能在updateItem()方法中获取字段对象,并且只有在那里我才能创建控件 在JavaFX7中,一切都很好,但在Java8中,我看不到我的控件 解决我的案子的方法正确吗 更新1 下面是复制问题的完整示例:

我有自定义ListView单元格我有带两个控件的HBox:

  • 带有名称字段的标签
  • 它必须从对象的上下文生成
  • 例如,我设置了类字段的ListView项数组、if field type Boolean i create复选框、if String i create TextField等

    问题是:我只能在updateItem()方法中获取字段对象,并且只有在那里我才能创建控件

    在JavaFX7中,一切都很好,但在Java8中,我看不到我的控件

    解决我的案子的方法正确吗

    更新1

    下面是复制问题的完整示例:

    package javafx8listviewexample;
    
    import java.lang.reflect.Field;
    import java.net.URL;
    import java.util.Date;
    import java.util.ResourceBundle;
    import javafx.collections.FXCollections;
    import javafx.event.ActionEvent;
    import javafx.fxml.FXML;
    import javafx.fxml.Initializable;
    import javafx.scene.control.DatePicker;
    import javafx.scene.control.ListCell;
    import javafx.scene.control.ListView;
    import javafx.scene.control.TextField;
    import javafx.scene.control.cell.TextFieldListCell;
    import javafx.util.Callback;
    
    /**
     *
     * @author dmitrynelepov
     */
    public class FXMLDocumentController implements Initializable {
    
        static class TestClassForListView {
    
            public String fieldString;
            public Date fieldDate;
        }
    
        static class MyListCell extends ListCell<Field> {
    
            /**
             * As in tutorial
             *
             * @param t
             * @param bln
             */
            @Override
            protected void updateItem(Field t, boolean bln) {
                super.updateItem(t, bln);
                if (t != null) {
                    if (t.getType().equals(String.class)) {
                        System.out.println("Draw string");
                        setGraphic(new TextField(t.getName()));
                    } else if (t.getType().equals(Date.class)) {
                        System.out.println("Draw Date");
                        setGraphic(new DatePicker());
    
                    }
                }
            }
    
        }
    
        @FXML
        private ListView<Field> listView;
    
        @FXML
        private void handleButtonAction(ActionEvent event) {
            this.listView.getItems().clear();
            this.listView.setItems(
                    FXCollections.observableArrayList(
                            TestClassForListView.class.getFields()
                    )
            );
        }
    
        @Override
        public void initialize(URL url, ResourceBundle rb) {
            this.listView.setCellFactory(new Callback<ListView<Field>, ListCell<Field>>() {
    
                @Override
                public ListCell<Field> call(ListView<Field> p) {
                    return new MyListCell();
                }
            });
    
        }
    
    }
    
    PackageJavaFX8ListViewExample;
    导入java.lang.reflect.Field;
    导入java.net.URL;
    导入java.util.Date;
    导入java.util.ResourceBundle;
    导入javafx.collections.FXCollections;
    导入javafx.event.ActionEvent;
    导入javafx.fxml.fxml;
    导入javafx.fxml.Initializable;
    导入javafx.scene.control.DatePicker;
    导入javafx.scene.control.ListCell;
    导入javafx.scene.control.ListView;
    导入javafx.scene.control.TextField;
    导入javafx.scene.control.cell.TextFieldListCell;
    导入javafx.util.Callback;
    /**
    *
    *@作者dmitrynelepov
    */
    公共类FXMLDocumentController实现可初始化{
    静态类TestClassForListView{
    公共字符串字段字符串;
    公共日期字段日期;
    }
    静态类MyListCell扩展了ListCell{
    /**
    *就像在教程中一样
    *
    *@param t
    *@param bln
    */
    @凌驾
    受保护的void updateItem(字段t,布尔bln){
    超级更新项(t,bln);
    如果(t!=null){
    if(t.getType().equals(String.class)){
    System.out.println(“绘制字符串”);
    setGraphic(新的文本字段(t.getName());
    }else如果(t.getType().equals(Date.class)){
    系统输出打印号(“提取日期”);
    setGraphic(新的日期选择器());
    }
    }
    }
    }
    @FXML
    私有列表视图列表视图;
    @FXML
    私有无效把手按钮操作(ActionEvent事件){
    this.listView.getItems().clear();
    this.listView.setItems(
    FXCollections.observableArrayList(
    TestClassForListView.class.getFields()
    )
    );
    }
    @凌驾
    公共void初始化(URL、ResourceBundle rb){
    this.listView.setCellFactory(新的回调函数(){
    @凌驾
    公共ListCell调用(ListView p){
    返回新的MyListCell();
    }
    });
    }
    }
    
    这里是程序JDK 7的屏幕截图

    正如你所看到的,文本字段可以被聚焦和编辑

    但是如果我用JDK 8运行这个例子,我得到


    在这里,您可以看到文本字段无法聚焦和编辑。

    看起来您需要一个控件fx:


    一个类似的实现,在对的回答中。尽管该问题的答案基于TableView,但ListView和TableView都是虚拟化控件,因此实现概念有点类似于使用问题中概述的带HBox的ListView


    根据问题中的示例代码进行更新

    我仍然认为ControlsFX PropertySheet似乎是您试图实现的最合适的解决方案。为此类任务使用虚拟化控件(如ListView)只会使事情变得更加复杂

    基于ListView的属性编辑器的完整解决方案非常复杂,超出了StackOverflow答案中合理提供的范围

    您在问题中提供的示例代码存在一些问题。ListView是一个虚拟化控件,因此您不应该在调用update时创建新的图形节点来放置在ListView中。发生的情况是,一个TextField获得焦点,然后在ListView上调用update,然后创建一个新的TextField,默认情况下,新的TextField没有焦点

    我认为ListView本身对于您的特定情况有一些实现问题,并且调用update的次数太多。不管怎样,您应该编写代码,以便能够适当地处理在单个单元格上多次调用的更新,并进行修改。如果您这样做,ListView调用您的方法的次数是否超过它需要的次数就无关紧要了

    下面是一些示例代码,可以帮助您取得更大的进步。我不认为示例代码是您问题的完整解决方案,它当然不是作为Java对象的综合属性编辑器提供的,但它可能会给您一些灵感,帮助您改进和实现代码(假设您决定继续尝试以这种方式解决此问题)。如果继续使用ListView,可能需要查看ListView的编辑例程(类似于Oracle JavaFX教程中的定义)

    导入javafx.application.application;
    导入javafx.beans.value.ChangeListener;
    导入javafx.collections.FXCollections;
    导入javafx.scene.scene;
    导入javafx.scene.control.*;
    导入javafx.stage.stage;
    导入java.lang.reflect.Field;
    导入java.time.LocalDate;
    /**
    *@作者dmitrynelepov
    *由Jewelsea修改
    */
    公共类已生存扩展应用程序{
    静态类TestClassForListView{
    公共字符串字段字符串;
    公共LocalDate字段日期;
    @凌驾
    公共字符串toString(){
    返回“TestClassForListView{”+
    “fieldString='”+fieldString+'\''+
    “,fieldDate=“+fieldDate+
    '}';
    }
    }
    静态类MyListCell扩展了ListCell{
    私有文本字段文本字段;
    私人日期选择器日期选择器;
    私有对象编辑对象;
    私有ChangeListener editCommitHandler;
    公共MyListCell(Obj
    
    import javafx.application.Application;
    import javafx.beans.value.ChangeListener;
    import javafx.collections.FXCollections;
    import javafx.scene.Scene;
    import javafx.scene.control.*;
    import javafx.stage.Stage;
    
    import java.lang.reflect.Field;
    import java.time.LocalDate;
    
    /**
     * @author dmitrynelepov
     * Modified by Jewelsea
     */
    public class EvilHasSurvived extends Application {
    
        static class TestClassForListView {
            public String fieldString;
            public LocalDate fieldDate;
    
            @Override
            public String toString() {
                return "TestClassForListView{" +
                        "fieldString='" + fieldString + '\'' +
                        ", fieldDate=" + fieldDate +
                        '}';
            }
        }
    
        static class MyListCell extends ListCell<Field> {
            private TextField textField;
            private DatePicker datePicker;
            private Object editedObject;
            private ChangeListener<Boolean> editCommitHandler;
    
            public MyListCell(Object editedObject) {
                this.editedObject = editedObject;
                setContentDisplay(ContentDisplay.RIGHT);
            }
    
            @Override
            protected void updateItem(Field t, boolean bln) {
                super.updateItem(t, bln);
    
                if (datePicker != null) {
                    datePicker.focusedProperty().removeListener(editCommitHandler);
                }
                if (textField != null) {
                    textField.focusedProperty().removeListener(editCommitHandler);
                }
    
                if (t == null) {
                    setText(null);
                    setGraphic(null);
                    return;
                }
    
                if (t.getType().equals(String.class)) {
                    if (textField == null) {
                        textField = new TextField();
                    }
    
                    editCommitHandler = (observable, oldValue, newValue) -> {
                        try {
                            t.set(editedObject, textField.getText());
                            System.out.println(editedObject + " for " + textField + " value " + textField.getText());
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    };
                    textField.focusedProperty().addListener(editCommitHandler);
    
                    setText(t.getName());
                    setGraphic(textField);
                } else if (t.getType().equals(LocalDate.class)) {
                    if (datePicker == null) {
                        datePicker = new DatePicker();
                    }
    
                    editCommitHandler = (observable, oldValue, newValue) -> {
                        try {
                            t.set(editedObject, datePicker.getValue());
                            System.out.println(editedObject + " for " + datePicker + " value " + datePicker.getValue());
                        } catch (IllegalAccessException e) {
                            e.printStackTrace();
                        }
                    };
                    datePicker.focusedProperty().addListener(editCommitHandler);
    
                    setText(t.getName());
                    setGraphic(datePicker);
                }
            }
        }
    
        @Override
        public void start(Stage stage) throws Exception {
            ListView<Field> listView = new ListView<>();
            listView.setItems(
                FXCollections.observableArrayList(
                    TestClassForListView.class.getFields()
                )
            );
            TestClassForListView testObject = new TestClassForListView();
            listView.setCellFactory(p -> new MyListCell(testObject));
    
            stage.setScene(new Scene(listView));
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);
        }
    }