如何根据 TableView 中的行元素自定义 TableCell/TableColumn 内容 (JavaFX)

Howto customize TableCell/TableColumn content according to its row element in TableView (JavaFX)

问题

我有一个 TableColumn<User, String> colPassword 目前 显示现有密码(字符串)作为每个条目(行)的屏蔽。

需要

我需要你的帮助,这样每个 TableCell 只显示 masked 密码: user.isManager == true,否则密码应该是unmasked.

我目前的做法

为了便于理解,我将只提供关键部分。

public class User implements Serializable {

    private Long id;
    private boolean deleted = false;
    private final BooleanProperty manager = new SimpleBooleanProperty();
    private final StringProperty password = new SimpleStringProperty("");

    public User() {
    }

    public boolean isManager() {
        return manager.get();
    }

    public void setManager(boolean value) {
        manager.set(value);
    }

    public BooleanProperty managerProperty() {
        return manager;
    }

GUI 用户控制器

public class UsersController {
    @FXML
    private TableView<User> tblUsers;
    @FXML
    private TableColumn<User, String> colPassword;

    private void initTableColumns() {
        colPassword.setCellValueFactory(cellData
                    -> cellData.getValue().passwordProperty()
        );
        colPassword.setCellFactory((TableColumn<User, String> param) -> {
            return new PasswordFieldCell();
        });
    }

这里是自定义的 TabelCell

public class PasswordFieldCell extends TableCell<User, String> {

    private final Label lbl;

    public PasswordFieldCell() {
        lbl = new Label();
        this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        this.setGraphic(null);
    }

    private String generatePasswordString(int len) {
        String dots = "";

        for (int i = 0; i < len; i++) {
            dots += "*";
        }

        return dots;
    }

    @Override
    protected void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (!empty) {
            lbl.setText(generatePasswordString(item.length()));
            setGraphic(lbl);
        } else {
            setGraphic(null);
        }
    }
}

解决方案

VGR 的帮助下,我在 PasswordFieldCell 中找到了这个解决方案。

public class PasswordFieldCell extends TableCell<User, String> {

    private final Label lbl;

    public PasswordFieldCell() {
        lbl = new Label();
        this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        this.setGraphic(null);
    }

    private String generatePasswordString(int len) {
        String dots = "";

        for (int i = 0; i < len; i++) {
            dots += "*";
        }

        return dots;
    }

    @Override
    protected void updateItem(String item, boolean empty) {
        super.updateItem(item, empty);
        if (!empty) {
            int row = getIndex();
            User user = getTableView().getItems().get(row);

            if (user.isManager()) { // mask password
                lbl.setText(generatePasswordString(item.length()));
            } else { // unmask password
                lbl.setText(item);
            }

            setGraphic(lbl);
        } else {
            setGraphic(null);
        }
    }
}

您的 PasswordFieldCell class 从 TableCell.

继承了很多有用的方法

特别是,您继承了一个 getTableView() 方法和一个 returns 当前单元格行的 getIndex() 方法。这些就是您在 updateItem 方法中查找单元格行值所需的全部内容:

int row = getIndex();
User user = getTableView().getItems().get(row);