javafx 如何将可用枚举列表添加到 ComboBoxTableCell?

javafx how do I add a list of available enums to ComboBoxTableCell?

无法弄清楚如何使用 ComboBox 将枚举列表添加到 table。目前代码无法编译,它在 StringConverter 的 grade.toString() 中失败。 以下是我正在使用的基本示例。最终我希望能够做三件事:

  1. 显示包含所有可用枚举的组合框

  2. 用当前成绩预填充它,如果有的话。

  3. 能够更改选择并使用新选择更新学生的对象。

有人可以帮忙吗?

public class App extends Application {
  @Override
  public void start(Stage stage) throws Exception {
    try {
      StackPane root = new StackPane();
      TableView<Student> tbl = new TableView<>();
      TableColumn<Student, Grade> col = new TableColumn<>("Grade");

      ObservableList<Grade> grades = FXCollections.observableArrayList(Grade.values());

      col.setCellFactory(ComboBoxTableCell.forTableColumn(new StringConverter<Grade>() {
        @Override
        public String toString(Grade grade) {
          return grade.toString();
        }
        @Override
        public Grade fromString(String s) {
          return Grade.valueOf(s);
        }
      }, grades));

      tbl.getColumns().add(col);

      Student a = new Student();
      a.grade = Grade.A;
      a.name = "Mark";
      tbl.setItems(FXCollections.observableArrayList(a));

      root.getChildren().add(tbl);

      Scene scene = new Scene(root, 800, 600);
      stage.setScene(scene);
      stage.show();
    }
    catch (Exception e) {
      e.printStackTrace();
    }
  }

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

枚举

public enum Grade {
  A (5),
  B (4),
  C (3),
  D (2),
  F (1);

  int gradePoints;

  Grade(int gradePoints) {
    this.gradePoints = gradePoints;
  }

  public int getGradePoints() {
    return gradePoints;
  }
}

和学生 class:

public class Student {
    String name; // name has the default value null 
    int age; // age has the default value 0 
    boolean isScienceMajor; // isScienceMajor has default value false 
    char gender; // gender has default value '\u0000' 
    Grade grade;
}

如何为 table 单元格定义值

您没有告诉系统如何找出单元格的值。

您需要在列上设置单元格值工厂。最简单的方法是让您的 Student class 使用和公开 JavaFX 属性,然后 set the cell value factory to a propertyValueFactory 命名与给定列关联的 属性。对于您的示例,这将是 "grade" 属性.

如何编辑单元格table

如果您希望 table 或特定列为 editable,您需要指定 the table is editable, and the columns are editable。您还需要在定义项目类型的 class 中公开适当的 setters 或 属性 方法。对于您的示例,这意味着在 Student class 中为您希望能够关联的每个字段定义适当的属性 and/or getter 和 setter 函数与 table.

正如 fabian 在评论中所建议的那样,为了稳健性,最好让 StringConverterComboBoxTableCell 能够处理空值(如下面提供的示例代码所示) ).

用户如何编辑项目

要开始编辑单元格,用户需要双击单元格以将其从显示模式转换为编辑模式(然后将显示组合框,但没有下拉列表)。然后单击组合框将其下拉,然后从下拉列表中选择适当的等级,之后将保存该值并将单元格切换回读取模式。系统会知道。根据 属性 值定义,调用适当的 setter 将新选择的等级保存回基础项目的等级 属性。

示例应用程序

App.java

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.ComboBoxTableCell;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class App extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage stage) throws Exception {
        StackPane root = new StackPane();
        TableView<Student> tbl = new TableView<>();
        tbl.setEditable(true);

        TableColumn<Student, String> nameCol = new TableColumn<>("Name");
        nameCol.setEditable(false);
        nameCol.setCellValueFactory(new PropertyValueFactory<>("name"));

        TableColumn<Student, Grade> gradeCol = new TableColumn<>("Grade");
        gradeCol.setEditable(true);

        ObservableList<Grade> grades = FXCollections.observableArrayList(Grade.values());
        gradeCol.setCellFactory(
                ComboBoxTableCell.forTableColumn(
                        new StringConverter<>() {
                            @Override
                            public String toString(Grade grade) {
                                return grade != null ? grade.toString() : null;
                            }

                            @Override
                            public Grade fromString(String s) {
                                return s != null ? Grade.valueOf(s) : null;
                            }
                        },
                        grades
                )
        );

        gradeCol.setCellValueFactory(new PropertyValueFactory<>("grade"));

        tbl.getColumns().addAll(nameCol, gradeCol);

        Student aStudent = new Student(
                "Mark", Grade.A
        );
        tbl.setItems(FXCollections.observableArrayList(aStudent));

        root.getChildren().add(tbl);

        Scene scene = new Scene(root);
        stage.setScene(scene);
        stage.show();
    }
}

Student.java

import javafx.beans.property.ObjectProperty;
import javafx.beans.property.ReadOnlyStringProperty;
import javafx.beans.property.ReadOnlyStringWrapper;
import javafx.beans.property.SimpleObjectProperty;

public class Student {
    private ReadOnlyStringWrapper name;
    private ObjectProperty<Grade> grade;

    public Student(String name, Grade grade) {
        this.name = new ReadOnlyStringWrapper(name);
        this.grade = new SimpleObjectProperty<>(grade);
    }

    public String getName() {
        return name.get();
    }

    public ReadOnlyStringProperty nameProperty() {
        return name.getReadOnlyProperty();
    }

    public Grade getGrade() {
        return grade.get();
    }

    public ObjectProperty<Grade> gradeProperty() {
        return grade;
    }

    public void setGrade(Grade grade) {
        this.grade.set(grade);
    }
}

成绩 class 与您问题中的定义没有变化。