Java ListView-如何正确配置单元格';什么是显示器?

Java ListView-如何正确配置单元格';什么是显示器?,java,listview,javafx,javafx-8,Java,Listview,Javafx,Javafx 8,我想定制列表视图单元格的显示。假设有一个ListView包含Person类的对象和两个按钮: 添加(生成)新的人员 要删除选定的人员 我希望实现以下目标: 未选择单元格时,它必须显示人员的getBasicView(),这是一个名称字段 当选择一个单元格时,它必须显示一个人的getExpandedView(),这是一个多行文本name+“/n”+姓氏 问题是什么 我编写的代码满足了上述要求,但出现了其他错误: 当添加一个新的Person进行眨眼操作时,单元格的显示将更改为未实现的toStrin

我想定制
列表视图
单元格的显示。假设有一个
ListView
包含
Person
类的对象和两个按钮:

  • 添加(生成)新的
    人员
  • 要删除选定的
    人员
我希望实现以下目标:

  • 未选择单元格时,它必须显示
    人员的
    getBasicView()
    ,这是一个
    名称
    字段
  • 当选择一个单元格时,它必须显示一个
    人的
    getExpandedView()
    ,这是一个多行文本
    name+“/n”+姓氏
  • 问题是什么

    我编写的代码满足了上述要求,但出现了其他错误:

  • 当添加一个新的
    Person
    进行眨眼操作时,单元格的显示将更改为未实现的
    toString()
    方法(因此用户会看到
    示例)。Person@c4f324
    类似垃圾)
  • 从最后一个单元格中删除
    人时,奇怪的事情开始发生。被删除的
    人员
    姓名
    仍保留在单元格中,该单元格向下移动了两个单元格,并且由于它不再包含
    人员
    对象,因此无法将其清除
  • 我尝试将侦听器添加到单元格的
    itemProperty
    ,它可以检查item是否为
    null
    ,在我可以将文本设置为
    之后,但不幸的是,它不起作用。有人知道如何使我的代码功能齐全吗

    提供SSCCE(假设所有文件都在
    示例
    包中):

    Main.java:

    package sample;
    
    import javafx.application.Application;
    import javafx.fxml.FXMLLoader;
    import javafx.scene.Parent;
    import javafx.scene.Scene;
    import javafx.stage.Stage;
    import java.io.IOException;
    
    public class Main extends Application {
    
      public void start(Stage stage) {
        FXMLLoader fxmlLoader = new FXMLLoader();
        fxmlLoader.setController(Controller.class);
        try {
          Parent parent = FXMLLoader.load(getClass().getResource("/sample/sample.fxml"));
          Scene scene = new Scene(parent);
          stage.setScene(scene);
          stage.show();
        } catch (IOException e) {
          e.printStackTrace();
        }
      }
    
      public static void main(String[] args) {
        launch();
      }
    }
    
    sample.fxml:

    <?import javafx.scene.layout.HBox?>
    <?import javafx.scene.control.Button?>
    <?import javafx.scene.control.ListView?>
    <?import javafx.scene.layout.VBox?>
    
    <HBox xmlns:fx="http://javafx.com/fxml" fx:controller="sample.Controller">
        <VBox>
            <Button text="Add Person" onAction="#addPerson"/>
            <Button text="Delete Person" onAction="#deletePerson"/>
        </VBox>
        <ListView prefHeight="400" prefWidth="400" fx:id="listView"/>
    </HBox>
    

    问题在于
    TextFieldListCell
    实现了单元格生命周期方法(
    updateItem
    等),并在不同点有效地调用
    setText(item.toString())
    。这显然干扰了您试图实现的行为。(例如,删除最后一个单元格的问题似乎是因为在
    TextFieldListCell
    将文本重置为其以前的值之前调用了
    setText(“”
    hack使其包围了完整的
    if
    -
    else
    子句,然后这个问题就消失了。但是…)

    如果不需要编辑单元格,则无需使用
    TextFieldListCell
    :只需使用普通的
    ListCell
    。(还要注意,对于已更改的项目/选定状态,处理程序中不需要
    平台.runLater(…)
    。)

    包装样品;
    导入java.util.concurrent.ThreadLocalRandom;
    导入javafx.collections.FXCollections;
    导入javafx.collections.ObservableList;
    导入javafx.fxml.fxml;
    导入javafx.scene.control.ListCell;
    导入javafx.scene.control.ListView;
    导入javafx.scene.control.multipleSelectModel;
    公共类控制器{
    @FXML
    私有列表视图列表视图;
    私有ObservableList personList=FXCollections.observableArrayList();
    私有字符串[]名称={“约翰”、“凯瑟琳”、“迈克尔”、“八月”、“彼得”};
    私人字符串[]姓氏={“琼斯”、“迈耶”、“史蒂文斯”、“韦恩”、“米尔顿”};
    @FXML
    私有void初始化(){
    初始化列表单元格();
    初始化列表();
    }
    私有无效初始值列表(){
    对于(int i=0;i<5;i++){
    添加(generatePerson());
    }
    setItems(personList);
    }
    私有void initializeListCells(){
    listView.setCellFactory(参数->{
    ListCell=新ListCell();
    cell.selectedProperty().addListener((可观察、旧值、新值)->handleCellDisplaying(单元格));
    cell.itemProperty().addListener((可观察、旧值、新值)->handleCellDisplaying(单元格));
    返回单元;
    });
    }
    私有void handlecell显示(列表单元格){
    Person=cell.getItem();
    if(person!=null){
    如果(!cell.isSelected()){
    cell.setText(person.getBasicView());
    }否则{
    cell.setText(person.getExpandedView());
    }
    }否则{
    cell.setText(“”);
    }
    }
    @FXML
    个人{
    添加(generatePerson());
    }
    @FXML
    私人{
    MultipleSelectionModel selectionModel=listView.getSelectionModel();
    如果(!selectionModel.isEmpty()){
    int-selectedIndex=selectionModel.getSelectedIndex();
    personList.remove(selectedIndex);
    }
    }
    私人发电人(){
    int nameRandom=ThreadLocalRandom.current().nextInt(1,5);
    int-namesrandom=ThreadLocalRandom.current().nextInt(1,5);
    返回新的人员(姓名[姓名随机]、姓氏[姓氏随机]);
    }
    }
    
    我假设1。在您的问题中,应改为“未选择单元格时”。你想让这些单元格可以编辑吗?@James_D Nope,只是显示而已。是的,未选中-我的不好。那么为什么要使用
    TextFieldListCell
    ?这已经在其整个生命周期中调用了
    setText(item.toString())
    ,这显然干扰了您正在定义的功能。只需使用一个普通的
    ListCell
    。你说你不能复制第二个bug?只需选择最后一项,然后继续单击“删除人员”按钮。@notmyf4ulty是的,刚刚解决。我现在可以复制了。如果在整个
    if
    -
    else
    中使用
    Platform.runLater(…)
    ,实际上可以消除这种情况,但是没有理由使用
    TextFieldListCell
    ,如果只使用
    ListCell
    (它从不调用
    setText()
    ),则不需要
    Platform.runLater()
    。这个例子是一个更复杂的案例(原始的
    列表视图package sample;
    
    import javafx.application.Platform;
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.fxml.FXML;
    import javafx.scene.control.ListView;
    import javafx.scene.control.MultipleSelectionModel;
    import javafx.scene.control.cell.TextFieldListCell;
    import java.util.concurrent.ThreadLocalRandom;
    
    public class Controller {
    
      @FXML
      private ListView<Person> listView;
      private ObservableList<Person> personList = FXCollections.observableArrayList();
      private String [] names = {"John", "Katherine", "Michael", "August", "Peter"};
      private String [] surnames = {"Jones", "Mayer", "Stevens", "Wayne", "Milton"};
    
      @FXML
      private void initialize() {
        initializeListCells();
        initializeList();
      }
    
      private void initializeList() {
        for (int i = 0 ; i < 5 ; i++) {
          personList.add(generatePerson());
        }
        listView.setItems(personList);
      }
    
      private void initializeListCells() {
        listView.setCellFactory(param -> {
          TextFieldListCell<Person> cell = new TextFieldListCell<Person>();
          cell.selectedProperty().addListener((observable, oldValue, newValue) -> handleCellDisplaying(cell));
          cell.itemProperty().addListener((observable, oldValue, newValue) -> handleCellDisplaying(cell));
          return cell;
        });
      }
    
      private void handleCellDisplaying(TextFieldListCell<Person> cell) {
        Person person = cell.getItem();
        if (person != null) {
          Platform.runLater(() -> {
            if (!cell.isSelected()) {
              cell.setText(person.getBasicView());
            } else {
              cell.setText(person.getExpandedView());
            }
          });
        } else {
          cell.setText("");
        }
      }
    
      @FXML
      private void addPerson() {
        personList.add(generatePerson());
      }
    
      @FXML
      private void deletePerson() {
        MultipleSelectionModel<Person> selectionModel = listView.getSelectionModel();
        if (!selectionModel.isEmpty()) {
          int selectedIndex = selectionModel.getSelectedIndex();
          personList.remove(selectedIndex);
        }
      }
    
      private Person generatePerson() {
        int nameRandom = ThreadLocalRandom.current().nextInt(1,5);
        int surnameRandom = ThreadLocalRandom.current().nextInt(1,5);
        return new Person(names[nameRandom],surnames[surnameRandom]);
      }
    }
    
    package sample;
    
    public class Person {
      private String name;
      private String surname;
    
      public Person(String name, String surname) {
        this.name = name;
        this.surname = surname;
      }
    
      public String getBasicView() {
        return name;
      }
    
      public String getExpandedView() {
        return name + "\n" + surname;
      }
    }
    
    package sample;
    
    import java.util.concurrent.ThreadLocalRandom;
    
    import javafx.collections.FXCollections;
    import javafx.collections.ObservableList;
    import javafx.fxml.FXML;
    import javafx.scene.control.ListCell;
    import javafx.scene.control.ListView;
    import javafx.scene.control.MultipleSelectionModel;
    
    public class Controller {
    
        @FXML
        private ListView<Person> listView;
        private ObservableList<Person> personList = FXCollections.observableArrayList();
        private String[] names = { "John", "Katherine", "Michael", "August", "Peter" };
        private String[] surnames = { "Jones", "Mayer", "Stevens", "Wayne", "Milton" };
    
        @FXML
        private void initialize() {
            initializeListCells();
            initializeList();
        }
    
        private void initializeList() {
            for (int i = 0; i < 5; i++) {
                personList.add(generatePerson());
            }
            listView.setItems(personList);
        }
    
        private void initializeListCells() {
            listView.setCellFactory(param -> {
                ListCell<Person> cell = new ListCell<Person>();
                cell.selectedProperty().addListener((observable, oldValue, newValue) -> handleCellDisplaying(cell));
                cell.itemProperty().addListener((observable, oldValue, newValue) -> handleCellDisplaying(cell));
                return cell;
            });
        }
    
        private void handleCellDisplaying(ListCell<Person> cell) {
            Person person = cell.getItem();
            if (person != null) {
                if (!cell.isSelected()) {
                    cell.setText(person.getBasicView());
                } else {
                    cell.setText(person.getExpandedView());
                }
            } else {
                cell.setText("");
            }
        }
    
        @FXML
        private void addPerson() {
            personList.add(generatePerson());
        }
    
        @FXML
        private void deletePerson() {
            MultipleSelectionModel<Person> selectionModel = listView.getSelectionModel();
            if (!selectionModel.isEmpty()) {
                int selectedIndex = selectionModel.getSelectedIndex();
                personList.remove(selectedIndex);
            }
        }
    
        private Person generatePerson() {
            int nameRandom = ThreadLocalRandom.current().nextInt(1, 5);
            int surnameRandom = ThreadLocalRandom.current().nextInt(1, 5);
            return new Person(names[nameRandom], surnames[surnameRandom]);
        }
    }