java - 根据用于填充表的列表元素中未显示的 java bean 值设置 JavaFX FXML 表行文本颜色

标签 java javafx fxml

我正在尝试将我在 swing 中构建的应用程序转换为 JavaFx。这包括彻底修改 GUI 设计。应用程序处理数据如下:

从数据库中检索数据。数据库中的每一行都被解析为一个 java bean,并且每个 bean 都被添加到一个 ArrayList 中。然后,数组列表返回到调用方法,然后解析为 ObservableList 以使其与 JavaFX TableView 兼容。然后,我通过添加每个 List 元素(它是一个 java bean)来填充该表。

值得注意的是,构成表的每一行的 Java bean 有 12 个元素。该表仅在 9 列中向用户显示其中的 9 个。我想要做的就是获取行列表元素中其他未显示的值之一,并使用它来确定显示行的文本颜色是否设置为红色或绿色。我似乎无法处理这个问题。我在 Stack 和其他论坛上查看了其他几个类似的问题,它们似乎解决了为特定单元格或列而不是行设置单元格文本颜色的问题。他们似乎还依赖可见的显示值来做到这一点。我尝试了几种方法,但似乎都不起作用,而且看起来很复杂。我想要做的事情必须有一种更直接的方法,因为这必须是一个相当普遍的要求。有人可以告诉我如何做到这一点吗?

我的表在 FXML 中定义如下:

 <TableView fx:id="toDoTable" editable="true" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
           <columns>
              <TableColumn fx:id="todoID" prefWidth="59.0" text="ID" />
              <TableColumn id="columnHeader" fx:id="Charity" prefWidth="77.0" text="Charity" />
              <TableColumn fx:id="todoFunder" prefWidth="101.0" text="Funder" />
              <TableColumn fx:id="todoType" prefWidth="92.0" text="Task Type" />
              <TableColumn fx:id="todoInternalDeadline" prefWidth="145.0" text="Internal Deadline" />
              <TableColumn fx:id="todoExternalDeadline" prefWidth="145.0" text="External Deadline" />
              <TableColumn fx:id="todoHrs" prefWidth="140.0" text="Target Hours" />
              <TableColumn fx:id="todoActualHrs" prefWidth="110.0" text="Actual Hours" />
              <TableColumn fx:id="todoDescription" prefWidth="110.0" text="Description" />
           </columns>
        </TableView>

该表在相应 Controller 类的初始化方法中填充,如下所示:

public void initialize(URL url, ResourceBundle rb) {

    todoID.setCellValueFactory(new PropertyValueFactory<>("taskID"));
    todoClient.setCellValueFactory(new PropertyValueFactory<>("Charity"));
    todoFunder.setCellValueFactory(new PropertyValueFactory<>("taskFunder"));
    todoType.setCellValueFactory((new PropertyValueFactory<>("taskType")));
    todoInternalDeadline.setCellValueFactory((new PropertyValueFactory<>("internalDeadline")));
    todoExternalDeadline.setCellValueFactory((new PropertyValueFactory<>("externalDeadline")));
    todoHrs.setCellValueFactory((new PropertyValueFactory<>("assignedHours")));
    todoActualHrs.setCellValueFactory((new PropertyValueFactory<>("hoursCompleted")));
    todoDescription.setCellValueFactory((new PropertyValueFactory<>("taskDescription")));

    ObservableList<Task> list = FXCollections.observableArrayList(parseTaskBeans());//parseTaskBeans();
    toDoTable.getItems().addAll(list);
    GuiUtility.autoResizeColumns(toDoTable);
    //toDoTable.getSelectionModel().setSelectionMode(SelectionMode.SINGLE);
    toDoTable.autosize(); 
}

虽然上面的内容将填充整个表格,但我认为我需要做的是单独处理行并在将它们添加到 View 之前对它们进行着色。我假设颜色必须是表元素而不是列表的属性,因为列表只是数据。我最近的尝试如下,但我认为它一定是完全错误的,因为我无法找到获取行中文本来定义其颜色的方法。所以我留下了评论,因为我认为我需要添加代码来解决这个问题:

    for(int i = 0; i<list.size(); i++){
        System.out.println(list.get(i).getTaskReturned());
        if(list.get(i).getTaskReturned().equalsIgnoreCase("false")){
            //set Color red
        }
            else{
            //set color green
            }
            toDoTable.getItems().add(list.get(i));
        }

我的另一个想法是使用 lambda 来处理表行内容,但我再次可以看到如何获取实际行。逐个单元地设置每个元素似乎非常复杂,因此必须有一种完全不同的方式来思考这个问题,而我没有得到。如果有人可以解释并告诉我如何做到这一点,我将不胜感激。

最佳答案

代码示例,希望对您有帮助:

public class Main extends Application {
    private TableView table = new TableView();
    @Override
    public void start(Stage primaryStage) throws Exception{
        ObservableList<Data> data = FXCollections.observableArrayList(
                new Data("Jacob", "Smith", true),
                new Data("Isabella", "Johnson",true),
                new Data("Ethan", "Williams", false),
                new Data("Emma", "Jones", true),
                new Data("Michael", "Brown", true)
        );
        TableColumn firstDataCol = new TableColumn("Data1");
        firstDataCol.setMinWidth(100);
        firstDataCol.setCellValueFactory(
                new PropertyValueFactory<Data, String>("data1"));

        TableColumn secondDataCol = new TableColumn("Data2");
        secondDataCol.setMinWidth(100);
        secondDataCol.setCellValueFactory(
                new PropertyValueFactory<Data, String>("data2"));

        /*TableColumn isGreenCol = new TableColumn("IsGreen");
        isGreenCol.setMinWidth(200);
        isGreenCol.setCellValueFactory(
                new PropertyValueFactory<Data, Boolean>("isGreen"));*/

        table.setRowFactory(new Callback<TableView<Data>, TableRow<Data>>() {
            @Override
            public TableRow<Data> call(TableView<Data> tableView) {
                final TableRow<Data> row = new TableRow<Data>() {
                    @Override
                    protected void updateItem(Data data, boolean empty){
                        super.updateItem(data, empty);
                        if (data!=null&&data.isGreen.get()) {
                           setStyle("-fx-text-background-color: green;");

                        } else {
                            setStyle("-fx-text-background-color: red;");
                        }
                    }
                };

                return row;
            }
        });

        table.setItems(data);
        table.getColumns().addAll(firstDataCol, secondDataCol);
        Parent window = new VBox();
        ((VBox) window).getChildren().add(new Label("example of small window:"));
        primaryStage.setTitle("example");
        ((VBox) window).getChildren().add(table);
        Scene scene=new Scene(window);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public class Data {
        private final SimpleStringProperty data1;
        private final SimpleStringProperty data2;
        private final SimpleBooleanProperty isGreen;

        public Data(String data1, String data2, Boolean isGreen) {
            this.data1 = new SimpleStringProperty(data1);
            this.data2 = new SimpleStringProperty(data2);
            this.isGreen = new SimpleBooleanProperty(isGreen);
        }

        public String getData1() {
            return data1.get();
        }

        public SimpleStringProperty data1Property() {
            return data1;
        }

        public String getData2() {
            return data2.get();
        }

        public SimpleStringProperty data2Property() {
            return data2;
        }

        public boolean isIsGreen() {
            return isGreen.get();
        }

        public SimpleBooleanProperty isGreenProperty() {
            return isGreen;
        }
    }
    public static void main(String[] args) {
        launch(args);
    }
}

输出屏幕:

enter image description here

Java 文档对其工作原理的解释:

setRowFactory:

A function which produces a TableRow. The system is responsible for reusing TableRows. Return from this function a TableRow which might be usable for representing a single row in a TableView.

Note that a TableRow is not a TableCell. A TableRow is simply a container for a TableCell, and in most circumstances it is more likely that you'll want to create custom TableCells, rather than TableRows. The primary use case for creating custom TableRow instances would most probably be to introduce some form of column spanning support.

You can create custom TableCell instances per column by assigning the appropriate function to the cellFactory property in the TableColumn class. @return rowFactory property

并对一行中的每个单元格进行 updateItem 调用:

updateItem:

The updateItem method should not be called by developers, but it is the best method for developers to override to allow for them to customise the visuals of the cell. To clarify, developers should never call this method in their code (they should leave it up to the UI control, such as the ListView control) to call this method. However, the purpose of having the updateItem method is so that developers, when specifying custom cell factories (again, like the ListView cell factory), the updateItem method can be overridden to allow for complete customisation of the cell. It is very important that subclasses of Cell override the updateItem method properly, as failure to do so will lead to issues such as blank cells or cells with unexpected content appearing within them. Here is an example of how to properly override the updateItem method:

protected void updateItem(T item, boolean empty) {
            super.updateItem(item, empty);

            if (empty || item == null) {
                setText(null);
                setGraphic(null);
            } else {
                setText(item.toString());
            }
        }

Note in this code sample two important points: We call the super.updateItem(T, boolean) method. If this is not done, the item and empty properties are not correctly set, and you are likely to end up with graphical issues. We test for the empty condition, and if true, we set the text and graphic properties to null. If we do not do this, it is almost guaranteed that end users will see graphical artifacts in cells unexpectedly. Overrides: updateItem in class Cell Params: data – The new item for the cell. empty – whether or not this cell represents data from the list. If it is empty, then it does not represent any domain data, but is a cell being used to render an "empty" row.

关于java - 根据用于填充表的列表元素中未显示的 java bean 值设置 JavaFX FXML 表行文本颜色,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52686756/

相关文章:

java - 依赖注入(inject) - 使用 <jsp :include>

css - 动态更改 CSS 中特定类的 JavaFX 属性

java - 如何使用不同的 fxml 文件创建多个 javafx Controller ?

java - Hibernate 合并不会删除 OneToMany 旧实体

java - Socket客户端+线程+Android+连接状态

java - 使用注解创建时,默认情况下如何命名Bean?

java - 在 JavaFX 应用程序线程上执行 TimerTasks 是否有比嵌套匿名 Runnable 更优雅的方法?

java - 如何在java中为多个按钮设置相同的操作/过程

java - 选择哪个 ChoiceBox-Event?

java - 如何使用 fxml JavaFX 运行 recorder.java?