java - 如何根据行项目的属性设置 TableCell 样式?
问题描述
我的应用程序有一个TableView
填充了对图像文件的引用列表。
数据从数据库加载,仅提供有关如何定位图像文件本身的信息(因此它指示图像的子文件夹和文件名)。
在我TableView
的 中,如果物理文件不存在,我想将“文件名”列的文本设置为红色。我已经实现了CellFactory
它,它“有点”工作......有时。该updateItem()
方法被覆盖以检查相关文件是否存在,但这并不总是正确的:一些行将使用红色文本设置样式,而其他行则不会,即使它们指向同一个文件。
此外,在滚动列表时,值可能会偶尔更改。
很难描述,所以我在下面创建了一个 MCVE。
主.java
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.io.File;
public class Main extends Application {
private ObservableList<DataItem> dataItems;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
initData();
// Main interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
// Setup the TableView
TableView<DataItem> tableView = new TableView<>();
TableColumn<DataItem, ImageCategory> colCategory = new TableColumn<>("Category");
TableColumn<DataItem, String> colFilename = new TableColumn<>("Filename");
// Initialize the column data
colCategory.setCellValueFactory(cellData -> cellData.getValue().categoryProperty());
colFilename.setCellValueFactory(cellData -> cellData.getValue().filenameProperty());
tableView.getColumns().add(colCategory);
tableView.getColumns().add(colFilename);
// Style text based on file exists
colFilename.setCellFactory(filenameCell -> new TableCell<DataItem, String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setStyle("");
} else {
// Check if file exists
DataItem thisItem = getTableView().getItems().get(getIndex());
File imageFile = new File("C:\\Users\\XXX\\Desktop\\"
+ thisItem.getCategory().getCategoryName() + "\\"
+ item);
if (!imageFile.exists()) {
setStyle("-fx-text-fill: red");
}
setText(item);
}
}
});
tableView.setItems(dataItems);
root.getChildren().add(tableView);
primaryStage.setScene(new Scene(root));
primaryStage.setWidth(300);
primaryStage.setHeight(200);
primaryStage.show();
}
private void initData() {
dataItems = FXCollections.observableArrayList();
for (int i = 0; i < 15; i++) {
dataItems.add(new DataItem(
new ImageCategory(1, "Application Icon"),
"icon.png"));
}
for (int i = 0; i < 15; i++) {
dataItems.add(new DataItem(
new ImageCategory(1, "Logo"),
"logo.png"));
}
}
}
数据项.java
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
class DataItem {
private SimpleObjectProperty<ImageCategory> category = new SimpleObjectProperty<>();
private SimpleStringProperty filename = new SimpleStringProperty();
public DataItem(ImageCategory category, String filename) {
this.category.set(category);
this.filename.set(filename);
}
public ImageCategory getCategory() {
return category.get();
}
public SimpleObjectProperty<ImageCategory> categoryProperty() {
return category;
}
public String getFilename() {
return filename.get();
}
public SimpleStringProperty filenameProperty() {
return filename;
}
}
ImageCategory.java
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
class ImageCategory {
private SimpleIntegerProperty categoryId = new SimpleIntegerProperty();
private SimpleStringProperty categoryName = new SimpleStringProperty();
public ImageCategory(int categoryId, String categoryName) {
this.categoryId.set(categoryId);
this.categoryName.set(categoryName);
}
public int getCategoryId() {
return categoryId.get();
}
public SimpleIntegerProperty categoryIdProperty() {
return categoryId;
}
public String getCategoryName() {
return categoryName.get();
}
public SimpleStringProperty categoryNameProperty() {
return categoryName;
}
@Override
public String toString() {
return getCategoryName();
}
}
显然,您需要一个示例文件来测试它。这是运行此结果的屏幕截图。请注意,Logo/logo.png
确实存在:
您会看到第一个“logo.png”的样式正确,为纯文本,但随后的条目似乎表明该文件不存在。调整窗口大小或滚动列表有时也会导致样式文本从一行更改为另一行;这是相当随机的。
如何准确测试该行表示的文件是否实际存在?
附带问题:在我的生产应用程序中,滚动非常缓慢且延迟,因为通过网络共享驱动器检查文件是否存在很慢。有没有办法将这些项目设置为第一次加载而不是每次渲染单元格时?
解决方案
关于不正确的单元格样式:
如果项目更改为现有项目,则无需更改样式。这意味着如果您从不存在的文件更改为现有文件,您的单元格文本将保持红色。您需要正确处理这种情况:
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty) {
setText(null);
setStyle("");
} else {
// Check if file exists
DataItem thisItem = getTableView().getItems().get(getIndex());
File imageFile = new File("C:\\Users\\XXX\\Desktop\\"
+ thisItem.getCategory().getCategoryName() + "\\"
+ item);
if (!imageFile.exists()) {
setStyle("-fx-text-fill: red");
} else {
// modification here ----------------------------------------------
setStyle("");
}
setText(item);
}
}
至于滚动问题:
updateItem
在 JavaFX 应用程序线程上运行。在此线程上执行长时间运行的操作(例如与远程目录通信)会使 UI 无响应。您可以通过将信息存储在项目类本身中或添加一些包含数据的结构(例如Map
.
与远程目录的通信仍应在单独的线程上完成。您可以按计划在EXISTENT
...NON_EXISTENT
UNKNOWN
Task
ExecutorService
推荐阅读
- python - PyTorch:在没有 CPU 传输的情况下渲染点云?
- casting - 在 Power BI 中将字符串列转换为 int
- javascript - CalendarList:列表不返回日历列表
- php - 查询内容最多的前 5 个类别,每个类别返回 5 个内容,并使用 laravel 将 associaled 用户名与内容连接起来
- java - 如何检测另一个应用程序浮动按钮是否在我们的应用程序之上?
- javascript - 为什么 Babel 7 不编译 node_modules 文件?
- javascript - 区域图中的角度 Highcharts 自定义图例标签
- java - 在不同的监视器 selenium webdriver java 上测试失败
- c# - 基于 [InlineData] 或 [MemberData] 的动态断言
- rest - Outlook 任务 REST API - 未授权 401