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