JavaFX2 TableView:不同的单元格工厂取决于单元格内的数据

JavaFX2 TableView:不同的单元格工厂取决于单元格内的数据,javafx,tableview,cell,factory,Javafx,Tableview,Cell,Factory,我正在尝试使用表视图来呈现/编辑“key=value”对。 所以这个表应该有两列:“key”和“value”。键只是一个普通字符串,值可以是任何值。我的问题是,各行的值的数据类型可能不同。基本上,我想使用布尔值的复选框和列表的选项。通过设置单元格工厂,我找到了一种使用复选框或选项呈现整个表格列的方法: final TableColumn<FieldValue, Field> valueColumn = new TableColumn<>("Value"); valueCo

我正在尝试使用表视图来呈现/编辑“key=value”对。 所以这个表应该有两列:“key”和“value”。键只是一个普通字符串,值可以是任何值。我的问题是,各行的值的数据类型可能不同。基本上,我想使用布尔值的复选框和列表的选项。通过设置单元格工厂,我找到了一种使用复选框或选项呈现整个表格列的方法:

final TableColumn<FieldValue, Field> valueColumn = new TableColumn<>("Value");
valueColumn.setCellFactory(new Callback<TableColumn<FieldValue, Field>, TableCell<FieldValue, Field>>() {
    @Override
    public TableCell<FieldValue, Field> call(final TableColumn<FieldValue, Field> column) {
        // if (value instanceof Boolean)
        return new CheckBoxTableCell<>();
    }
});
final TableColumn valueColumn=新TableColumn(“值”);
valueColumn.setCellFactory(新回调(){
@凌驾
公共TableCell调用(最终TableColumn列){
//if(布尔值实例)
返回新的CheckBoxTableCell();
}
});

但我需要的是能够根据要在单元格内呈现的项的类型插入一个条件。换句话说,某些单元格工厂位于单元格级别,而不是列级别。这将在渲染时评估我的条件。我还没有找到任何解决办法。也许有人有一些合适的技术来实现这种渲染?可能是第三方数据网格?

这里有一个表格,显示了不同类型的字符串和对象对

自定义单元工厂用于处理不同对象类型的显示(通过对对象类型执行instanceof检查并呈现适当的文本或图形)

导入javafx.application.*;
导入javafx.beans.property.ReadOnlyObjectWrapper;
导入javafx.beans.value.observeValue;
导入javafx.collections.*;
导入javafx.scene.scene;
导入javafx.scene.control.*;
导入javafx.scene.image.*;
导入javafx.scene.layout.*;
导入javafx.stage.stage;
导入javafx.util.Callback;
导入javafx.util.Pair;
公共类可对扩展应用程序{
公共静态最终字符串名称\u列\u NAME=“NAME”;
公共静态最终字符串值\u列\u NAME=“VALUE”;
最终的TableView表格=新的TableView();
公共静态void main(字符串[]args)引发异常{
发射(args);
}
public void start(final Stage)引发异常{
//模型数据
ObservableList data=FXCollections.observableArrayList(
配对(“歌曲”,“巴赫大提琴组曲2”),
配对(“图像”,新图像(“http://upload.wikimedia.org/wikipedia/en/9/99/Bach_Seal.jpg")),
成对(“额定值”,4),
配对(“经典”,真实),
成对(“歌曲数据”,新字节[]{})
);
table.getItems().setAll(数据);
表2.设置高度(275);
//表定义
TableColumn nameColumn=新的TableColumn(名称\列\名称);
nameColumn.setPrefWidth(100);
TableColumn valueColumn=新的TableColumn(值\列\名称);
valueColumn.setSortable(假);
valueColumn.setPrefWidth(150);
nameColumn.setCellValueFactory(新的PairKeyFactory());
setCellValueFactory(新的PairValueFactory());
table.getColumns().setAll(nameColumn,valueColumn);
valueColumn.setCellFactory(新回调(){
@凌驾
公共TableCell调用(TableColumn列){
返回新的PairValueCell();
}
});
//布置场景。
最终StackPane布局=新StackPane();
layout.getChildren().setAll(表);
场景=新场景(布局);
舞台场景;
stage.show();
}
专用对(字符串名称、对象值){
返回新对(名称、值);
}
}
类PairKeyFactory实现回调{
@凌驾
公共observeValue调用(TableColumn.CellDataFeatures数据){
返回新的ReadOnlyObjectWrapper(data.getValue().getKey());
}
}
类PairValueFactory实现回调{
@抑制警告(“未选中”)
@凌驾
公共observeValue调用(TableColumn.CellDataFeatures数据){
对象值=data.getValue().getValue();
返回值(ObservalEvalue的值实例)
?(可观察值)值
:新的只读对象包装器(值);
}
}
类PairValueCell扩展了TableCell{
@凌驾
受保护的void updateItem(对象项,布尔值为空){
super.updateItem(项,空);
如果(项!=null){
if(字符串的项目实例){
setText((字符串)项);
设置图形(空);
}else if(整数的项目实例){
setText(Integer.toString((Integer)项));
设置图形(空);
}else if(布尔值的项实例){
复选框=新复选框();
复选框.setSelected((布尔)项);
设置图形(复选框);
}else if(图像的项目实例){
setText(空);
ImageView ImageView=新的ImageView((图像)项);
imageView.setFitWidth(100);
imageView.setPreserveRatio(真);
imageView.setSmooth(真);
设置图形(图像视图);
}否则{
setText(“不适用”);
设置图形(空);
}
}否则{
setText(空);
设置图形(空);
}
}
}

这就是我在这个主题上花了多一点时间后最终选择做的事情。谢谢你的回答!我不确定“updateItem”方法是否是唯一一个重写以获得良好结果的方法,但对于您的示例,它似乎工作得很好,但现在单元格是只读的。。。知道如何使它们可编辑吗?请作为新问题提问
import javafx.application.*;
import javafx.beans.property.ReadOnlyObjectWrapper;
import javafx.beans.value.ObservableValue;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.Pair;

public class PairTable extends Application {
    public static final String NAME_COLUMN_NAME  = "Name";
    public static final String VALUE_COLUMN_NAME = "Value";

    final TableView<Pair<String, Object>> table = new TableView<>();

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

    public void start(final Stage stage) throws Exception {
        // model data
        ObservableList<Pair<String, Object>> data = FXCollections.observableArrayList(
                pair("Song", "Bach Cello Suite 2"),
                pair("Image", new Image("http://upload.wikimedia.org/wikipedia/en/9/99/Bach_Seal.jpg")),
                pair("Rating", 4),
                pair("Classic", true),
                pair("Song Data", new byte[]{})
        );

        table.getItems().setAll(data);
        table.setPrefHeight(275);

        // table definition
        TableColumn<Pair<String, Object>, String> nameColumn = new TableColumn<>(NAME_COLUMN_NAME);
        nameColumn.setPrefWidth(100);
        TableColumn<Pair<String, Object>, Object> valueColumn = new TableColumn<>(VALUE_COLUMN_NAME);
        valueColumn.setSortable(false);
        valueColumn.setPrefWidth(150);

        nameColumn.setCellValueFactory(new PairKeyFactory());
        valueColumn.setCellValueFactory(new PairValueFactory());

        table.getColumns().setAll(nameColumn, valueColumn);
        valueColumn.setCellFactory(new Callback<TableColumn<Pair<String, Object>, Object>, TableCell<Pair<String, Object>, Object>>() {
            @Override
            public TableCell<Pair<String, Object>, Object> call(TableColumn<Pair<String, Object>, Object> column) {
                return new PairValueCell();
            }
        });

        // layout the scene.
        final StackPane layout = new StackPane();
        layout.getChildren().setAll(table);
        Scene scene = new Scene(layout);
        stage.setScene(scene);
        stage.show();
    }

    private Pair<String, Object> pair(String name, Object value) {
        return new Pair<>(name, value);
    }
}

class PairKeyFactory implements Callback<TableColumn.CellDataFeatures<Pair<String, Object>, String>, ObservableValue<String>> {
    @Override
    public ObservableValue<String> call(TableColumn.CellDataFeatures<Pair<String, Object>, String> data) {
        return new ReadOnlyObjectWrapper<>(data.getValue().getKey());
    }
}

class PairValueFactory implements Callback<TableColumn.CellDataFeatures<Pair<String, Object>, Object>, ObservableValue<Object>> {
    @SuppressWarnings("unchecked")
    @Override
    public ObservableValue<Object> call(TableColumn.CellDataFeatures<Pair<String, Object>, Object> data) {
        Object value = data.getValue().getValue();
        return (value instanceof ObservableValue)
                ? (ObservableValue) value
                : new ReadOnlyObjectWrapper<>(value);
    }
}

class PairValueCell extends TableCell<Pair<String, Object>, Object> {
    @Override
    protected void updateItem(Object item, boolean empty) {
        super.updateItem(item, empty);

        if (item != null) {
            if (item instanceof String) {
                setText((String) item);
                setGraphic(null);
            } else if (item instanceof Integer) {
                setText(Integer.toString((Integer) item));
                setGraphic(null);
            } else if (item instanceof Boolean) {
                CheckBox checkBox = new CheckBox();
                checkBox.setSelected((boolean) item);
                setGraphic(checkBox);
            } else if (item instanceof Image) {
                setText(null);
                ImageView imageView = new ImageView((Image) item);
                imageView.setFitWidth(100);
                imageView.setPreserveRatio(true);
                imageView.setSmooth(true);
                setGraphic(imageView);
            } else {
                setText("N/A");
                setGraphic(null);
            }
        } else {
            setText(null);
            setGraphic(null);
        }
    }
}