如何将自定义单元格工厂用于表视图



如何轻松地将自定义(可重用)cellFactory应用于javafx.scene.control.TableCell;javafx.scene.control.TableView;

要应用自定义单元格工厂来格式化单元格中显示的文本、其颜色等,以下示例可能会有所帮助。

初始情况

假设您有一个 Bean/POJO Person

public class Person {
    private double levelOfGrowth = 0;
    public Person() {};
    public Person(double levelOfGrowth) {
        this.levelOfGrowth = levelOfGrowth;
    };
    public double getLevelOfGrowth() {
        return levelOfGrowth;
    }
}

其中levelOfGrowth是一个人成长完成程度的百分比值。

它可能设置在 0.00 到 1.00 之间。

我们还假设您已在绑定到控制器MainWindowController的 FXML 中创建视图。您还可以设置列以显示对 id levelOfGrowth levelOfGrowthColumn

public class MainWindowController implements Initializable {
    @FXML
    public TableColumn levelOfGrowthColumn;
    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        ObservableList<Person> persons = FXCollections.observableArrayList();
        persons.add(new Person(0));
        persons.add(new Person(0.5));
        persons.add(new Person(1));
        levelOfGrowthColumn.setCellValueFactory(new PropertyValueFactory<Person, Double>("levelOfGrowth"));
    }
}

意图

上面示例中的问题是视图中显示的值类似于 0.5 而不是 50%。我们还可能希望将 100% 等值的颜色更改为绿色。

解决方案

我们需要的是一个(可重用的)类,它描述了如何在视图中格式化/打印双精度值并将该类与levelOfGrowthColumn连接起来。

"格式化程序"类

public class PercantageFormatCell extends TableCell<Object, Double> {
    public PercantageFormatCell() {
    }
    @Override
    protected void updateItem(Double item, boolean empty) {
        super.updateItem(item, empty);
        // If the row is not empty but the Double-value is null,
        // we will always display 0%
        if (!empty && null == item) {
            item = new Double(0.0d);
        }
        // Here we set the displayed text to anything we want without changing the
        // real value behind it. We could also have used switch case or anything you
        // like.
        setText(item == null ? "" : NumberFormat.getPercentInstance().format(item));
        // If the cell is selected, the text will always be white
        // (so that it can be read against the blue background),
        // if the value is 1 it will be green.
        if (item != null) {
            double value = item.doubleValue();
            if (isFocused() || isSelected() || isPressed()) {
                setTextFill(Color.WHITE);
            } else if (value < 1) {
                setTextFill(Color.BLACK);
            } else {
                setTextFill(Color.GREEN);
            }
        }
    }
}

在控制器中使用它

public class MainWindowController implements Initializable {
    @FXML
    public TableColumn levelOfGrowthColumn;
    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        ObservableList<Person> persons = FXCollections.observableArrayList();
        persons.add(new Person(0));
        persons.add(new Person(0.5));
        persons.add(new Person(1));
        // New code START
        // In case we have multiple columns with percent-values it
        // might come in handy to store our formatter
        Callback<TableColumn, TableCell> percantageCellFactory =
            new Callback<TableColumn, TableCell>() {
                public TableCell call(TableColumn p) {
                    return new PercantageFormatCell();
                }
            };
        // Now all we have to do is to apply it
        levelOfGrowthColumn.setCellFactory(percantageCellFactory);
        // New code END
        levelOfGrowthColumn.setCellValueFactory(new PropertyValueFactory<Person, Double>("levelOfGrowth"));
    }
}

最新更新