如何在 TableView 中正确设置图像
How to correctly set images inside TableView
我正在尝试使用将 ImageView 作为其值之一的对象来填充表格视图,但只有表格视图中的最后一项显示图像,其余的 none
public class MainController implements Initializable {
public TableView<Apple> table;
public TableColumn nameColumn;
public TableColumn imageColumn;
ImageView imageView = new ImageView(new Image("download.jpg"));
Apple apple = new Apple("Bob",imageView);
Apple apple2 = new Apple("John",imageView);
Apple[] apples = {apple2,apple};
List<Apple> appleList = Arrays.asList(apples);
@Override
public void initialize(URL location, ResourceBundle resources) {
imageColumn.setCellValueFactory(new PropertyValueFactory<>("image"));
nameColumn.setCellValueFactory((new PropertyValueFactory<>("name")));
table.setItems(FXCollections.observableArrayList(appleList));
}
}
public class Apple {
private final int SIZE = 20;
String name;
ImageView image;
public Apple(String name, ImageView image) {
this.name = name;
this.image = image;
image.setFitHeight(SIZE);
image.setFitWidth(SIZE);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ImageView getImage() {
return image;
}
public void setImage(ImageView image) {
this.image = image;
}
}
我不确定为什么会这样,不过我在网上看到有人使用循环将图像 1 对 1 设置。
如@jewelsea 的评论所述,您的模型 class (Apple
) 应仅包含数据;它不应包含 UI 字段,例如 ImageView
。任何 Node
只能在场景图中出现一次,这就是为什么您只能在 table.
的一行中看到 ImageView
您应该将图像的路径或 Image
(仅是数据)本身存储在模型 class 中。这两种选择之间的权衡是计算时间与内存消耗的权衡。如果您存储图像的路径,则每次单元格更新时(例如在滚动期间)都需要加载图像,这需要时间。另一方面,如果您存储 Image
,那么整个 table 所需的所有图像都需要存储在内存中,无论它们是否显示。
如果您的 table 只需要少量图像,我建议将 Image
存储在模型 class 中。如果 table 只有几行,或者图像数量较少且多行显示同一图像,则可能会发生这种情况。请注意,Image
s 可以 由多个 ImageView
s 共享,因此无需多次加载任何单个 Image
。
在模型 class 中使用 Image
将如下所示:
public class Apple {
private String name;
private Image image;
public Apple(String name, Image image) {
this.name = name;
this.image = image;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
}
您将需要一个单元格实现来显示图像:
public class ImageCell extends TableCell<Apple, Image> {
private static final IMAGE_SIZE = 20 ;
private final ImageView imageView ;
public TableCell() {
imageView = new ImageView();
imageView.setFitWidth(IMAGE_SIZE);
imageView.setFitHeight(IMAGE_SIZE);
imageView.setPreserveRatio(true);
}
@Override
protected void updateItem(Image image, boolean empty) {
if (empty || item == null) {
setGraphic(null);
} else {
imageView.setImage(image);
setGraphic(imageView);
}
}
}
您的应用程序代码如下所示:
public class MainController implements Initializable {
public TableView<Apple> table;
public TableColumn<Apple, String> nameColumn;
public TableColumn<Apple, Image> imageColumn;
Image downloadImage = new Image("download.jpg");
Apple apple = new Apple("Bob",downloadImage);
Apple apple2 = new Apple("John",downloadImage);
@Override
public void initialize(URL location, ResourceBundle resources) {
imageColumn.setCellValueFactory(cellData -> new SimpleObjectProperty<>(cellData.getValue().getImage()));
imageColumn.setCellFactory(column -> new ImageCell());
nameColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getName()));
table.setItems(FXCollections.observableArrayList(apple2, apple));
}
}
如果您在 table 中有大量不同的图像,这可能不太可能,您应该在模型中表示图像的路径 class 而不是:
public class Apple {
private String name;
private String imagePath;
public Apple(String name, String imagePath) {
this.name = name;
this.imagePath = imagePath;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getImagePath() {
return imagePath;
}
public void setImage(String imagePath) {
this.imagePath = imagePath;
}
}
然后你的单元格class需要加载图像:
public class ImageCell extends TableCell<Apple, String> {
private static final IMAGE_SIZE = 20 ;
private final ImageView imageView ;
public TableCell() {
imageView = new ImageView();
imageView.setFitWidth(IMAGE_SIZE);
imageView.setFitHeight(IMAGE_SIZE);
imageView.setPreserveRatio(true);
}
@Override
protected void updateItem(String imagePath, boolean empty) {
if (empty || item == null) {
setGraphic(null);
} else {
imageView.setImage(new Image(imagePath));
setGraphic(imageView);
}
}
}
并且您的应用程序代码有明显的修改:
public class MainController implements Initializable {
public TableView<Apple> table;
public TableColumn<Apple, String> nameColumn;
public TableColumn<Apple, String> imageColumn;
Apple apple = new Apple("Bob", "download.jpg");
Apple apple2 = new Apple("John", "download.jpg");
@Override
public void initialize(URL location, ResourceBundle resources) {
imageColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getImagePath()));
imageColumn.setCellFactory(column -> new ImageCell());
nameColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getName()));
table.setItems(FXCollections.observableArrayList(apple2, apple));
}
}
我正在尝试使用将 ImageView 作为其值之一的对象来填充表格视图,但只有表格视图中的最后一项显示图像,其余的 none
public class MainController implements Initializable {
public TableView<Apple> table;
public TableColumn nameColumn;
public TableColumn imageColumn;
ImageView imageView = new ImageView(new Image("download.jpg"));
Apple apple = new Apple("Bob",imageView);
Apple apple2 = new Apple("John",imageView);
Apple[] apples = {apple2,apple};
List<Apple> appleList = Arrays.asList(apples);
@Override
public void initialize(URL location, ResourceBundle resources) {
imageColumn.setCellValueFactory(new PropertyValueFactory<>("image"));
nameColumn.setCellValueFactory((new PropertyValueFactory<>("name")));
table.setItems(FXCollections.observableArrayList(appleList));
}
}
public class Apple {
private final int SIZE = 20;
String name;
ImageView image;
public Apple(String name, ImageView image) {
this.name = name;
this.image = image;
image.setFitHeight(SIZE);
image.setFitWidth(SIZE);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ImageView getImage() {
return image;
}
public void setImage(ImageView image) {
this.image = image;
}
}
我不确定为什么会这样,不过我在网上看到有人使用循环将图像 1 对 1 设置。
如@jewelsea 的评论所述,您的模型 class (Apple
) 应仅包含数据;它不应包含 UI 字段,例如 ImageView
。任何 Node
只能在场景图中出现一次,这就是为什么您只能在 table.
ImageView
您应该将图像的路径或 Image
(仅是数据)本身存储在模型 class 中。这两种选择之间的权衡是计算时间与内存消耗的权衡。如果您存储图像的路径,则每次单元格更新时(例如在滚动期间)都需要加载图像,这需要时间。另一方面,如果您存储 Image
,那么整个 table 所需的所有图像都需要存储在内存中,无论它们是否显示。
如果您的 table 只需要少量图像,我建议将 Image
存储在模型 class 中。如果 table 只有几行,或者图像数量较少且多行显示同一图像,则可能会发生这种情况。请注意,Image
s 可以 由多个 ImageView
s 共享,因此无需多次加载任何单个 Image
。
在模型 class 中使用 Image
将如下所示:
public class Apple {
private String name;
private Image image;
public Apple(String name, Image image) {
this.name = name;
this.image = image;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Image getImage() {
return image;
}
public void setImage(Image image) {
this.image = image;
}
}
您将需要一个单元格实现来显示图像:
public class ImageCell extends TableCell<Apple, Image> {
private static final IMAGE_SIZE = 20 ;
private final ImageView imageView ;
public TableCell() {
imageView = new ImageView();
imageView.setFitWidth(IMAGE_SIZE);
imageView.setFitHeight(IMAGE_SIZE);
imageView.setPreserveRatio(true);
}
@Override
protected void updateItem(Image image, boolean empty) {
if (empty || item == null) {
setGraphic(null);
} else {
imageView.setImage(image);
setGraphic(imageView);
}
}
}
您的应用程序代码如下所示:
public class MainController implements Initializable {
public TableView<Apple> table;
public TableColumn<Apple, String> nameColumn;
public TableColumn<Apple, Image> imageColumn;
Image downloadImage = new Image("download.jpg");
Apple apple = new Apple("Bob",downloadImage);
Apple apple2 = new Apple("John",downloadImage);
@Override
public void initialize(URL location, ResourceBundle resources) {
imageColumn.setCellValueFactory(cellData -> new SimpleObjectProperty<>(cellData.getValue().getImage()));
imageColumn.setCellFactory(column -> new ImageCell());
nameColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getName()));
table.setItems(FXCollections.observableArrayList(apple2, apple));
}
}
如果您在 table 中有大量不同的图像,这可能不太可能,您应该在模型中表示图像的路径 class 而不是:
public class Apple {
private String name;
private String imagePath;
public Apple(String name, String imagePath) {
this.name = name;
this.imagePath = imagePath;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getImagePath() {
return imagePath;
}
public void setImage(String imagePath) {
this.imagePath = imagePath;
}
}
然后你的单元格class需要加载图像:
public class ImageCell extends TableCell<Apple, String> {
private static final IMAGE_SIZE = 20 ;
private final ImageView imageView ;
public TableCell() {
imageView = new ImageView();
imageView.setFitWidth(IMAGE_SIZE);
imageView.setFitHeight(IMAGE_SIZE);
imageView.setPreserveRatio(true);
}
@Override
protected void updateItem(String imagePath, boolean empty) {
if (empty || item == null) {
setGraphic(null);
} else {
imageView.setImage(new Image(imagePath));
setGraphic(imageView);
}
}
}
并且您的应用程序代码有明显的修改:
public class MainController implements Initializable {
public TableView<Apple> table;
public TableColumn<Apple, String> nameColumn;
public TableColumn<Apple, String> imageColumn;
Apple apple = new Apple("Bob", "download.jpg");
Apple apple2 = new Apple("John", "download.jpg");
@Override
public void initialize(URL location, ResourceBundle resources) {
imageColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getImagePath()));
imageColumn.setCellFactory(column -> new ImageCell());
nameColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getName()));
table.setItems(FXCollections.observableArrayList(apple2, apple));
}
}