有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

根据用于填充表的列表元素中未显示的JavaBean值设置JavaFXML表行文本颜色

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

从数据库中检索数据。数据库中的每一行都被解析为一个Javabean,每个bean都被添加到一个ArrayList中。然后将数组列表返回给调用方法,然后解析为ObservableList,使其与JavaFXTableView兼容。然后,我通过向表中添加每个列表元素(一个JavaBean)来填充该表

值得注意的是,组成表的每一行的JavaBean有12个元素。该表在其9列中仅向用户显示其中的9个。我试图做的是,获取rows列表元素中其他未显示的值之一,并使用该值确定显示行的文本颜色是否设置为红色或绿色。我似乎无法处理这件事。我在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>

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

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(); 
}

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

    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来处理表中的行内容,但我可以再次看到如何处理实际的行。一个单元格一个单元格地设置每个元素似乎真的很复杂,所以一定有一种完全不同的方式来思考这个问题,我不明白。如果有人能解释并告诉我怎么做,我将不胜感激


共 (1) 个答案

  1. # 1 楼答案

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

    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.