1

我正在尝试将我在 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>

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

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

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

    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 来处理表格行内容,但我再次可以看到我是如何获得实际行的。逐个单元格地设置每个元素似乎真的很令人费解,因此必须有一种完全不同的方式来考虑这一点,而我没有得到。如果有人可以解释并告诉我如何做到这一点,我将不胜感激。

4

1 回答 1

2

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

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

输出屏幕:

在此处输入图像描述

Java Doc 对其工作原理的解释:

设置行工厂:

产生 TableRow 的函数。系统负责重用 TableRows。从此函数返回一个 TableRow,它可能可用于表示 TableView 中的单行。

请注意,TableRow不是TableCell。TableRow 只是 TableCell 的容器,在大多数情况下,您更可能想要创建自定义 TableCell,而不是 TableRows。创建自定义 TableRow 实例的主要用例很可能是引入某种形式的列跨越支持。

您可以通过将适当的函数分配给 TableColumn 类中的 cellFactory 属性来为每列创建自定义 TableCell 实例。@return 行工厂属性

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

更新项目:

updateItem 方法不应由开发人员调用,但它是开发人员重写以允许他们自定义单元格的视觉效果的最佳方法。澄清一下,开发人员不应该在他们的代码中调用这个方法(他们应该把它留给 UI 控件,例如 ListView 控件)来调用这个方法。但是,使用 updateItem 方法的目的是让开发人员在指定自定义单元工厂(再次,如 ListView 单元工厂)时,可以覆盖 updateItem 方法以允许对单元进行完全自定义。Cell 的子类正确覆盖 updateItem 方法非常重要,否则会导致出现空白单元格或单元格中出现意外内容等问题。

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

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

请注意此代码示例中的两个重要点: 我们调用 super.updateItem(T, boolean) 方法。如果不这样做,则 item 和 empty 属性设置不正确,您最终可能会遇到图形问题。我们测试空条件,如果为真,我们将文本和图形属性设置为空。如果我们不这样做,几乎可以保证最终用户会意外地看到单元格中的图形伪影。覆盖: 类 Cell 中的 updateItem 参数: data – 单元格的新项目。空 - 此单元格是否表示列表中的数据。如果它是空的,那么它不代表任何域数据,而是一个用于呈现“空”行的单元格。

于 2018-10-07T14:52:45.327 回答