JavaFX-更改TableView中选定TableRow的TableCell列

JavaFX-更改TableView中选定TableRow的TableCell列,java,javafx,tableview,tablecell,Java,Javafx,Tableview,Tablecell,我有一个包含自定义列和图像的TableView。其他列由ObservableList填充,但不是自定义列 双击该行时,我想更改该图像,但不知道如何获取TableCell对象,我只获取包含其他列数据的ObservableList(在代码中查找TODO) 下面是一些示例代码: import javafx.application.Application; import javafx.beans.property.SimpleStringProperty; import javafx.collectio

我有一个包含自定义列和图像的TableView。其他列由ObservableList填充,但不是自定义列

双击该行时,我想更改该图像,但不知道如何获取TableCell对象,我只获取包含其他列数据的ObservableList(在代码中查找TODO)

下面是一些示例代码:

import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Label;
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.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.VBox;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;

public class TableViewSample extends Application {

    private TableView<Person> table = new TableView<>();

    private final ObservableList<Person> data =
            FXCollections.observableArrayList(
                    new Person("Jacob", "Smith"),
                    new Person("Isabella", "Johnson"),
                    new Person("Ethan", "Williams"),
                    new Person("Emma", "Jones"),
                    new Person("Michael", "Brown")
            );


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


    @Override
    public void start(Stage stage) {
        Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(450);
        stage.setHeight(500);

        Label label = new Label("Address Book");
        label.setFont(new Font("Arial", 20));

        table.setEditable(true);

        TableColumn<Person, String> firstNameCol = new TableColumn<>("Name");
        firstNameCol.setMinWidth(100);
        firstNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("firstName"));

        TableColumn<Person, String> lastNameCol = new TableColumn<>("Last Name");
        lastNameCol.setMinWidth(100);
        lastNameCol.setCellValueFactory(new PropertyValueFactory<Person, String>("lastName"));

        TableColumn<Person, String> customCol = new TableColumn<>("Status");
        customCol.setMinWidth(200);
        // Install custom cell renderer
        customCol.setCellFactory(new Callback<TableColumn<Person, String>, TableCell<Person, String>>() {

            @Override
            public TableCell<Person, String> call(TableColumn<Person, String> param) {

                TableCell<Person, String> cell = new TableCell<Person, String>() {

                    ImageView image = new ImageView (new Image ("grey.png"));

                    @Override
                    public void updateItem (String item, boolean empty) {

                        super.updateItem (item, empty);

                        if (empty) {

                            setGraphic  (null);
                            setText     (null);
                        }
                        else {

                            setGraphic  (image);
                            setText     (null);
                        }
                    }
                };

                return cell;
            }

        });

        table.setItems(data);
        table.getColumns().addAll(firstNameCol, lastNameCol, customCol);

        table.setOnMousePressed ((event) -> {

            if (event.getClickCount() == 2) {

                System.out.println("double clicked, but dunno know how to change last columns image??");

            // TODO Only returns data of the other columns, but nothing from my custom column ...
            System.out.println(this.table.getSelectionModel().getSelectedItems());
            }
        });

        VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table);

        ((Group) scene.getRoot()).getChildren().addAll(vbox);

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



    public static class Person {

        private final SimpleStringProperty firstName;
        private final SimpleStringProperty lastName;

        private Person(String fName, String lName) {
            this.firstName = new SimpleStringProperty(fName);
            this.lastName = new SimpleStringProperty(lName);
        }

        public String getFirstName() {
            return firstName.get();
        }

        public void setFirstName(String fName) {
            firstName.set(fName);
        }

        public String getLastName() {
            return lastName.get();
        }

        public void setLastName(String fName) {
            lastName.set(fName);
        }
    }

}
导入javafx.application.application;
导入javafx.beans.property.SimpleStringProperty;
导入javafx.collections.FXCollections;
导入javafx.collections.ObservableList;
导入javafx.geometry.Insets;
导入javafx.scene.Group;
导入javafx.scene.scene;
导入javafx.scene.control.Label;
导入javafx.scene.control.TableCell;
导入javafx.scene.control.TableColumn;
导入javafx.scene.control.TableView;
导入javafx.scene.control.cell.PropertyValueFactory;
导入javafx.scene.image.image;
导入javafx.scene.image.ImageView;
导入javafx.scene.layout.VBox;
导入javafx.scene.text.Font;
导入javafx.stage.stage;
导入javafx.util.Callback;
公共类TableViewSample扩展了应用程序{
private TableView table=new TableView();
私有最终可观测列表数据=
FXCollections.observableArrayList(
新人(“雅各布”、“史密斯”),
新人(“伊莎贝拉”、“约翰逊”),
新人(“伊桑”、“威廉姆斯”),
新人(“艾玛”、“琼斯”),
新人(“迈克尔”、“布朗”)
);
公共静态void main(字符串[]args){
发射(args);
}
@凌驾
公众假期开始(阶段){
场景=新场景(新组());
stage.setTitle(“表格视图示例”);
舞台布景宽度(450);
舞台设置高度(500);
标签=新标签(“地址簿”);
label.setFont(新字体(“Arial”,20));
table.setEditable(true);
TableColumn firstNameCol=新的TableColumn(“名称”);
firstNameCol.setMinWidth(100);
firstNameCol.setCellValueFactory(新属性ValueFactory(“firstName”));
TableColumn lastNameCol=新的TableColumn(“姓氏”);
lastNameCol.setMinWidth(100);
lastNameCol.setCellValueFactory(新属性ValueFactory(“lastName”));
TableColumn customCol=新的TableColumn(“状态”);
自定义设置最小宽度(200);
//安装自定义单元渲染器
customCol.setCellFactory(新回调(){
@凌驾
公共TableCell调用(TableColumn参数){
TableCell单元格=新的TableCell(){
ImageView图像=新图像视图(新图像(“grey.png”);
@凌驾
public void updateItem(字符串项,布尔值为空){
super.updateItem(项,空);
if(空){
设置图形(空);
setText(空);
}
否则{
设置图形(图像);
setText(空);
}
}
};
返回单元;
}
});
表2.设置项目(数据);
table.getColumns().addAll(firstNameCol、lastNameCol、customCol);
table.setOnMousePressed((事件)->{
if(event.getClickCount()==2){
System.out.println(“双击,但不知道如何更改最后一列图像??);
//TODO只返回其他列的数据,但不从我的自定义列返回任何数据。。。
System.out.println(this.table.getSelectionModel().getSelectedItems());
}
});
VBox VBox=新的VBox();
vbox.setspace(5);
设置填充(新的插入(10,0,0,10));
vbox.getChildren().addAll(标签、表格);
((组)scene.getRoot()).getChildren().addAll(vbox);
舞台场景;
stage.show();
}
公共静态类人员{
私有最终SimpleStringProperty名字;
私有最终SimpleStringProperty姓氏;
私人(字符串fName,字符串lName){
this.firstName=新的SimpleStringProperty(fName);
this.lastName=新的SimpleStringProperty(lName);
}
公共字符串getFirstName(){
返回firstName.get();
}
public void setFirstName(字符串fName){
firstName.set(fName);
}
公共字符串getLastName(){
返回lastName.get();
}
public void setLastName(字符串fName){
lastName.set(fName);
}
}
}
也许有人能给我建议如何改变最后一列的图像

非常感谢并致以良好的问候


Wiesi;)

你的问题不是很精确,但也许这有帮助。此示例显示了
s的表格。它维护一组已成功验证的
项。(在本例中,如果项目的值为偶数,则该项目有效。)如果项目未成功验证(即无效或未执行验证),则第三列显示一个红色矩形的图像,如果项目已验证(即其值为偶数且已执行验证),则显示一个绿色矩形的图像。如果未成功验证,双击表中的行将对该项执行验证(因此双击偶数值项将使其图像变为绿色,双击奇数值项将无效)。(双击已验证的项目将其从验证集中删除,从而使测试更容易。)

它的工作方式是维护一个表示已验证项目的
可观察集
。单元值工厂返回一个布尔绑定,该绑定观察该集合,如果该项为i,则计算结果为true
import java.util.Random;
import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableSet;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.stage.Stage;

public class TableWithValidationColumn extends Application {

    private final Image validImage = createImage(20, 20, Color.GREEN);
    private final Image invalidImage = createImage(20, 20, Color.RED);

    @Override
    public void start(Stage primaryStage) {
        TableView<Item> table = new TableView<>();
        table.getColumns().add(column("Item", Item::nameProperty));
        table.getColumns().add(column("Value", Item::valueProperty));

        TableColumn<Item, Boolean> validColumn = new TableColumn<>("Validated");

        ObservableSet<Item> validItems = FXCollections.observableSet();

        validColumn.setCellValueFactory(cellData -> {
            Item item = cellData.getValue() ;
            return Bindings.createBooleanBinding(() -> validItems.contains(item), validItems);
        });

        validColumn.setCellFactory(col -> new TableCell<Item, Boolean>() {
            private final ImageView imageView = new ImageView();
            @Override
            protected void updateItem(Boolean valid, boolean empty) {
                super.updateItem(valid, empty);
                if (empty) {
                    setGraphic(null);
                } else {
                    if (valid) {
                        imageView.setImage(validImage);
                    } else {
                        imageView.setImage(invalidImage);
                    }
                    setGraphic(imageView);
                }
            }
        });

        table.getColumns().add(validColumn);

        // validate on double-click:

        table.setRowFactory(tv -> {
            TableRow<Item> row = new TableRow<>();
            row.setOnMouseClicked(e -> {
                if ((! row.isEmpty())  && e.getClickCount() == 2) {
                    Item item = row.getItem() ;
                    if (validItems.contains(item)) {
                        validItems.remove(item);
                    } else {
                        if (validate(item)) {
                            validItems.add(item);
                        }
                    }
                }
            });
            return row ;
        });

        Random rng = new Random();
        for (int i = 1 ; i <= 100 ; i++) {
            table.getItems().add(new Item("Item "+i, rng.nextInt(100)));
        }

        BorderPane root = new BorderPane(table);
        Scene scene = new Scene(root, 600 ,600);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private boolean validate(Item item) {
        // items with even values validate:
        return item.getValue() % 2 == 0;
    }

    private static <S,T> TableColumn<S,T> column(String text, Function<S, ObservableValue<T>> property) {
        TableColumn<S,T> col = new TableColumn<>(text);
        col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        return col ;
    }

    private final Image createImage(int w, int h, Color color) {
        Rectangle rect = new Rectangle(w, h, color);
        return rect.snapshot(null, null);
    }

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

    public static class Item {
        private final StringProperty name = new SimpleStringProperty();
        private final IntegerProperty value = new SimpleIntegerProperty();

        public Item(String name, int value) {
            setName(name);
            setValue(value);
        }

        public final StringProperty nameProperty() {
            return this.name;
        }


        public final String getName() {
            return this.nameProperty().get();
        }


        public final void setName(final String name) {
            this.nameProperty().set(name);
        }


        public final IntegerProperty valueProperty() {
            return this.value;
        }


        public final int getValue() {
            return this.valueProperty().get();
        }


        public final void setValue(final int value) {
            this.valueProperty().set(value);
        }



    }
}