javafx 根据项目自定义TableCell外观

示例

有时,一列应该显示的内容不仅仅是toString单元格项目的值。在这种情况下,由TableCell的创建cellFactory的会TableColumn被自定义,以根据项目更改布局。

重要说明: TableView仅创建TableCellUI中显示的。单元格内的项目可以更改,甚至变空。程序员需要注意撤消TableCell对删除项的添加所做的任何更改。否则,内容可能仍会显示在“不属于”的单元格中。

在以下示例中,设置项目会导致设置文本以及显示在中的图像ImageView:

image.setImage(item.getEmoji());
setText(item.getValue());

如果该项变为null或单元格为空,则通过将值设置回以下来撤消那些更改null:

setText(null);
image.setImage(null);


以下示例显示了中除文字外的表情符号TableCell。

updateItem每次Cell更改a的项目时都会调用此方法。重写此方法可以对更改做出反应并调整单元格的外观。将侦听器添加到itemProperty()单元的可以是一种替代方法,但是在许多情况下TableCell可以扩展。

物品种类

import javafx.scene.image.Image;

// 枚举提供某些感觉的图像和文本
public enum Feeling {
    HAPPY("happy", "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Emojione_1F600.svg/64px-Emojione_1F600.svg.png"),
    SAD("sad", "https://upload.wikimedia.org/wikipedia/commons/thumb/4/42/Emojione_1F62D.svg/64px-Emojione_1F62D.svg.png")
    ;
    private final Image emoji;
    private final String value;

    Feeling(String value, String url) {
        // 在背景中加载图片
        emoji = new Image(url, true);
       this.value= value;
    }

    public Image getEmoji() {
        return emoji;
    }

    public String getValue() {
        return value;
    }
    
}

应用程序类中的代码

import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

public class EmotionTable extends Application {

    public static class Item {

        private final ObjectProperty<Feeling> feeling;

        public Item(Feeling feeling) {
           this.feeling= new SimpleObjectProperty<>(feeling);
        }

        public final Feeling getFeeling() {
            return this.feeling.get();
        }

        public final void setFeeling(Feeling value) {
            this.feeling.set(value);
        }

        public final ObjectProperty<Feeling> feelingProperty() {
            return this.feeling;
        }

    }

    @Override
    public void start(Stage primaryStage) {
        TableView<Item> table = new TableView<>(FXCollections.observableArrayList(
                new Item(Feeling.HAPPY),
                new Item(Feeling.HAPPY),
                new Item(Feeling.HAPPY),
                new Item(Feeling.SAD),
                null,
                new Item(Feeling.HAPPY),
                new Item(Feeling.HAPPY),
                new Item(Feeling.SAD)
        ));

        EventHandler<ActionEvent> eventHandler = new EventHandler<ActionEvent>() {

            @Override
            public void handle(ActionEvent event) {
                // 根据源用户数据更改表项
                Node source = (Node) event.getSource();
                Feeling targetFeeling = (Feeling) source.getUserData();
                for (Item item : table.getItems()) {
                    if (item != null) {
                        item.setFeeling(targetFeeling);
                    }
                }
            }

        };

        TableColumn<Item, Feeling> feelingColumn = new TableColumn<>("Feeling");

        feelingColumn.setCellValueFactory(new PropertyValueFactory<>("feeling"));

        // 使用自定义表格单元格显示表情符号图像
        feelingColumn.setCellFactory(new Callback<TableColumn<Item, Feeling>, TableCell<Item, Feeling>>() {

            @Override
            public TableCell<Item, Feeling> call(TableColumn<Item, Feeling> param) {
                return new EmojiCell<>();
            }
        });

        table.getColumns().add(feelingColumn);

        Button sunshine = new Button("sunshine");
        Button rain = new Button("rain");

        sunshine.setOnAction(eventHandler);
        rain.setOnAction(eventHandler);

        sunshine.setUserData(Feeling.HAPPY);
        rain.setUserData(Feeling.SAD);

        Scene scene = new Scene(new VBox(10, table, new HBox(10, sunshine, rain)));

        primaryStage.setScene(scene);
        primaryStage.show();
    }

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

}

单元类别

import javafx.scene.control.TableCell;
import javafx.scene.image.ImageView;

public class EmojiCell<T> extends TableCell<T, Feeling> {

    private final ImageView image;

    public EmojiCell() {
        // 将ImageView添加为图形以显示它
        // 到单元格中的文本
        image = new ImageView();
        image.setFitWidth(64);
        image.setFitHeight(64);
        image.setPreserveRatio(true);

        setGraphic(image);
        setMinHeight(70);
    }

    @Override
    protected void updateItem(Feeling item, boolean empty) {
        super.updateItem(item, empty);

        if (empty || item == null) {
            // 回到空单元格的外观
            setText(null);
            image.setImage(null);
        } else {
            // 为非空单元格设置图像和文本
            image.setImage(item.getEmoji());
            setText(item.getValue());
        }
    }
}