具有自定义控件的JavaFX8 TableView

时间:2014-04-09 09:17:10

标签: java custom-controls tableview javafx-8

我想在TableView中使用自定义控件(代码中的ClientControl)。因此我创建了一个ClientCell类:

    public class NewClientCell extends TableCell<Client, Client> {
    private final ClientControl cc;

    public NewClientCell(ObservableList<Client> suggestions) {
        cc = new ClientControl(this.getItem(), suggestions);
        this.setAlignment(Pos.CENTER_LEFT);
        this.setGraphic(cc);
        this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
    }
@Override
protected void updateItem(Client c, boolean empty) {
    super.updateItem(c, empty);
    if(!empty){
        setGraphic(cc);
    }
}
}

在主程序中,我使用以下代码填写表格:

        TableColumn<Client, Client> clmClients = new TableColumn<>("Klient");
    clmClients.setCellFactory(new Callback<TableColumn<Client, Client>, TableCell<Client, Client>>() {
        @Override
        public TableCell<Client, Client> call(TableColumn<Client, Client> p) {
            return new NewClientCell(suggestions);
        };
    });

    clmClients.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Client, Client>, ObservableValue<Client>>() { 
        @Override
        public ObservableValue<Client> call(TableColumn.CellDataFeatures<Client, Client> p) {
            return new SimpleObjectProperty<Client>(p.getValue());
        }
    });
    getColumns().add(clmClients);

表中的数据来自ObservableList,并且初始化正确。

我现在的问题是自定义控件需要一个Client-Object,它应该从ObservableList中获取,但是“this.getItem()”总是返回null。

如何将客户端对象正确地放入自定义控件?

谢谢!

修改

这是ClientControl的构造函数:

    public ClientControl(Client client, ObservableList<Client> suggestions) {
    setClient(client);
    setSuggestions(suggestions);
    FXMLLoader loader = new FXMLLoader(getClass().getResource("ClientControl.fxml"));
    loader.setRoot(this);
    loader.setController(this);
    try {
        loader.load();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    initTextField();
    setLabelText(client.toString());
}

方法setClient是一个简单的setter方法(this.client = client;)。变量客户端和建议就是这么简单的定义:

    private ObservableList<Client> suggestions;
private Client client;

2 个答案:

答案 0 :(得分:1)

AFAIK,你应该像你一样在构造函数中实例化任何控件,这样它们只会被创建一次(请记住,单元格会被重用于不同的位置)。

但是你需要覆盖一个或多个其他方法,例如updateItem,以便从当前项目中获取数据。

修改

嗯,你正在分配相同的控件,而不是一遍又一遍地改变它。不是在updateItem方法中设置图形,而是设置客户端控件的item属性:

@Override
protected void updateItem(Client c, boolean empty) {
    super.updateItem(c, empty);
    if(!empty){
        cc.setClient(c);
    } else {
        cc.setClient(null);
    }
}

修改2

ClientControl应该将客户端项目作为属性而不是构造函数参数提供,并将其设置在updateItem方法中,而不是在构造函数中。

E.g。这样的事情(未经测试!):

private final ObjectProperty<Client> client = new SimpleObjectProperty<>(this, "client");
public final Client getClient(){
    return clientProperty().get();
}
public final void setClient(Client client){
    clientProperty().set(client);
}

public ObjectProperty<Client> clientProperty(){
    return client;
}

在构造函数中:侦听此属性的更改以设置labelText等。 您还可能希望提供没有客户端参数的构造函数,因为在TableCell构造函数中实例化它时它不可用。

答案 1 :(得分:0)

所以我找到了解决问题的方法。非常感谢Puce的帮助! :-) 现在我通过属性设置客户端:

    private ObjectProperty<Client> clientProperty = new SimpleObjectProperty<Client>();

另外,我在ClientControl的构造函数中添加了一个ChangeListener:

    public ClientControl(ObservableList<Client> suggestions) {
    clientProperty.addListener(new ChangeListener<Client>() {
        @Override
        public void changed(ObservableValue<? extends Client> observable, Client oldValue,
                ClientnewValue) {
            if(newValue != null) {
                setLabelText(newValue.toString());
            }
        }
    });
    setSuggestions(suggestions);
    FXMLLoader loader = new FXMLLoader(getClass().getResource("ClientControl.fxml"));
    loader.setRoot(this);
    loader.setController(this);
    try {
        loader.load();
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
    initTextField();
}

由于ClientControl中的更改,我的ClientCell类只需要一些简单的更改:

public class NewClientCell extends TableCell<Client, Client> {
private final ClientControl cc;

public NewClientCell(ObservableList<Client> suggestions) {
    cc = new ClientControl(suggestions);
this.setAlignment(Pos.CENTER_LEFT);
this.setGraphic(cc);
this.setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
}

@Override
protected void updateItem(Client c, boolean empty) {
    super.updateItem(c, empty);
    if(!empty){
        cc.setClient(c);
    }
}
}

在主程序中没有任何改变。

总之,我想再次感谢Puce,我坚持了很多天这个问题......