JavaFX - 更改 TableView 中选定 TableRow 的 TableCell 列
JavaFX - Change TableCell column of selected TableRow in a TableView
我有一个包含带有图像的自定义列的 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);
}
}
}
也许有人可以给我建议如何更改最后一栏的图像?
非常感谢和最诚挚的问候
维斯 ;)
你的问题不是很准确,但也许这有帮助。此示例显示 table 个 Item
。它维护一组已成功验证的 Item
。 (在此示例中,如果项目的值为偶数,则该项目有效。)如果项目未成功验证(即无效,或尚未执行验证),则第三列显示红色矩形图像和绿色矩形矩形,如果它已经过验证(即它具有偶数值并且已执行验证)。 Double-clicking 如果未成功验证,table 中的一行将对该项目执行验证(因此双击 even-valued 项目会将其图像变为绿色,双击 odd-valued 项将无效)。 (Double-clicking already-validated 项目会将其从验证集中删除,这使测试更容易。)
它的工作方式是维护一个 ObservableSet<Item>
表示已验证的项目。单元格值工厂 returns 一个布尔绑定,它观察该集合,如果该项目在集合中则计算为 true,否则计算为 false。细胞工厂只是 returns 一个检查布尔值并设置适当图像的细胞。
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);
}
}
}
我有一个包含带有图像的自定义列的 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);
}
}
}
也许有人可以给我建议如何更改最后一栏的图像?
非常感谢和最诚挚的问候
维斯 ;)
你的问题不是很准确,但也许这有帮助。此示例显示 table 个 Item
。它维护一组已成功验证的 Item
。 (在此示例中,如果项目的值为偶数,则该项目有效。)如果项目未成功验证(即无效,或尚未执行验证),则第三列显示红色矩形图像和绿色矩形矩形,如果它已经过验证(即它具有偶数值并且已执行验证)。 Double-clicking 如果未成功验证,table 中的一行将对该项目执行验证(因此双击 even-valued 项目会将其图像变为绿色,双击 odd-valued 项将无效)。 (Double-clicking already-validated 项目会将其从验证集中删除,这使测试更容易。)
它的工作方式是维护一个 ObservableSet<Item>
表示已验证的项目。单元格值工厂 returns 一个布尔绑定,它观察该集合,如果该项目在集合中则计算为 true,否则计算为 false。细胞工厂只是 returns 一个检查布尔值并设置适当图像的细胞。
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);
}
}
}