JavaFX 2 TableView:根据单元格内的数据不同的单元格工厂

Posted

技术标签:

【中文标题】JavaFX 2 TableView:根据单元格内的数据不同的单元格工厂【英文标题】:JavaFX 2 TableView : different cell factory depending on the data inside the cell 【发布时间】:2013-06-08 16:22:41 【问题描述】:

我正在尝试使用表格视图来呈现/编辑“key = value”对。 所以该表应该有两列:“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<>();
    
);

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

【问题讨论】:

【参考方案1】:

这是一个表格,显示了成对的字符串和各种类型的对象。

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

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);
        
    

【讨论】:

这就是我在这个主题上花了更多时间后最终选择做的事情。感谢您的回答!我不确定“updateItem”方法是否是唯一要覆盖以获得良好结果的方法,但对于您的示例,它似乎工作得很好 工作,但现在单元格是只读的......知道如何使它们可编辑吗? 请作为一个新问题询问 Eddy

以上是关于JavaFX 2 TableView:根据单元格内的数据不同的单元格工厂的主要内容,如果未能解决你的问题,请参考以下文章

TableView单元格内的TableView,自动调整单元格高度

javafx GridPane 检索特定的单元格内容

发生单元格内容交互时更新 TableView 单元格高度

将数据从firebase加载到集合单元格内的tableview

tableview单元格内的ios文本字段

tableView 单元格内的多个 collectionView 单元格在滚动时更改设计