简体   繁体   English

在 JavaFX 8 中,如何根据同一行的另一个单元格中的值更改单元格的背景颜色

[英]In JavaFX 8 how can I change the background color of a cell according to the value in another cell of the same row

I have a TableView in my application.我的应用程序中有一个TableView Two of the columns are payment date and expiration date.其中两列是付款日期和到期日期。 In each row, I want to change the background color of individual expiration date cells based on the value of the payment date cell in the same row.在每一行中,我想根据同一行中的付款日期单元格的值更改各个到期日期单元格的背景颜色。 My best attempt is here:我最好的尝试是在这里:

public class App extends Application {

    private final TableView<Bill> tableView = new TableView<>();

    private final TableColumn<Bill, Date>   tableColumnExpirationDate;
    private final TableColumn<Bill, Date>   tableColumnPaymentDate;

    public App() {
        ...
        this.tableColumnExpirationDate  = new TableColumn<>("Expires");
        this.tableColumnPaymentDate     = new TableColumn<>("Paid");

        Callback<TableColumn<Bill, Date>, TableCell<Bill, Date>>
                defaultTextFieldCellFactory = 
                TextFieldTableCell.<Bill, Date>forTableColumn(
                        new DateStringConverter());

        tableColumnExpirationDate.setCellFactory(col -> {
                TableCell<Bill, Date> cell = defaultTextFieldCellFactory.call(col);
                Bill bill = tableView.getItems().get(cell.getIndex());
                System.out.println("Bill: " + bill);
                cell.setStyle("-fx-background-color: red;");
                return cell;
        });

        tableColumnExpirationDate.setOnEditCommit(
                new EventHandler<CellEditEvent<Bill, Date>>() {

                @Override
                public void handle(CellEditEvent<Bill, Date> t) {
                    // I NEED TO BE ABLE:
                    // (1) Read the 'paymentDate' field of the same row.
                    // (2) Change the color of the background of this 
                    // 'expirationDate' cell, in this row.
                    Bill bill = (Bill) t.getTableView()
                                        .getItems()
                                        .get(t.getTablePosition().getRow());

                    bill.setExpirationDate(t.getNewValue());

                    Date paymentDate = bill.getPaymentDate();
                    long now = new Date().getTime();
                    now -= now % MILLISECONDS_PER_DAY;

                    long expirationMoment = bill.getExpirationDate().getTime();

                    if (paymentDate == null) {
                        long daysLeft = (expirationMoment - now) /
                                         MILLISECONDS_PER_DAY;

                    } else {
                        long paymentMoment = paymentDate.getTime();
                        paymentMoment -= paymentMoment % MILLISECONDS_PER_DAY;

                        long days = (expirationMoment - paymentMoment) /
                                     MILLISECONDS_PER_DAY;

                        System.out.println("Days paid before: " + days);

                    }
                }
            }
        );

        tableColumnPaymentDate.setOnEditCommit(
                new EventHandler<CellEditEvent<Bill, Date>>() {

                @Override
                public void handle(CellEditEvent<Bill, Date> t) {
                    ((Bill) t.getTableView()
                             .getItems()
                             .get(t.getTablePosition()
                                   .getRow()))
                             .setPaymentDate(t.getNewValue());
                }
            }
        );
    }

    ...
}

Everything needed to run the app is here .运行应用程序所需的一切都在这里

More concretely, whenever I am setting the background color of the expiration date cell, I cannot find the way for taking a look to another cell in the same row.更具体地说,每当我设置到期日期单元格的背景颜色时,我都找不到查看同一行中另一个单元格的方法。

The cleanest way to do this is probably to use a row factory that changes the style class, or a psuedo class, on the table row.最简洁的方法可能是使用行工厂来更改表行上的样式类或伪类。 Then just set a fixed style class on the cell.然后只需在单元格上设置一个固定的样式类。

In my examples, I use LocalDate instead of the legacy Date type;在我的示例中,我使用LocalDate而不是旧的Date类型; you can do something like你可以做类似的事情

PseudoClass nearlyExpired = PseudoClass.getPseudoClass("nearly-expired");

table.setRowFactory(tv -> {
    TableRow<Bill> row = new TableRow<>() ;
    BooleanProperty nearlyDueProperty = new SimpleBooleanProperty();
    nearlyDueProperty.addListener((obs, wasNearlyDue, isNearlyDue) -> 
        row.pseudoClassStateChanged(nearlyExpired, isNearlyDue));
    row.itemProperty().addListener((obs, oldBill, newBill) -> {
        nearlyDueProperty.unbind();
        if (newBill == null) {
            nearlyDueProperty.set(false);
        } else {

            // bind nearlyDueProperty to the time between the current Bill's
            // paymentDate and expirationDate
            // true if less than 7 days, false otherwise:

            nearlyDueProperty.bind(Bindings.createBooleanBinding(() -> 
                    newBill.getExpirationDate().minusDays(7).isBefore(newBill.getPaymentDate()),
                    newBill.expirationDateProperty(), newBill.paymentDateProperty()));
        }
    });

    return row ;
});

and then for the column itself you just need然后对于列本身,您只需要

LocalDateStringConverter converter = new LocalDateStringConverter();
Callback<TableColumn<Bill, LocalDate>, TableCell<Bill, LocalDate>> defaultCellFactory = TextFieldTableCell.forTableColumn(converter);
expirationDateCol.setCellFactory(tc -> {
    TableCell<Bill, LocalDate> cell = defaultCellFactory.call(tc);
    cell.getStyleClass().add("expiration-cell");
    return cell ;
});

and finally you can attach an external style sheet with最后你可以附加一个外部样式表

.table-row-cell:nearly-expired .expiration-cell {
    -fx-background-color: red ;
}

Obviously you can define the styles any way you like here.显然,您可以在此处以任何您喜欢的方式定义样式。

Here is a complete example:这是一个完整的例子:

import java.time.LocalDate;
import java.util.Random;
import java.util.function.Function;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.property.BooleanProperty;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.Property;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.css.PseudoClass;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.TextFieldTableCell;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.converter.LocalDateStringConverter;

public class BillingTable extends Application {

    @Override
    public void start(Stage primaryStage) {
        TableView<Bill> table = new TableView<>();
        table.setEditable(true);

        PseudoClass nearlyExpired = PseudoClass.getPseudoClass("nearly-expired");

        table.setRowFactory(tv -> {
            TableRow<Bill> row = new TableRow<>() ;
            BooleanProperty nearlyDueProperty = new SimpleBooleanProperty();
            nearlyDueProperty.addListener((obs, wasNearlyDue, isNearlyDue) -> 
                row.pseudoClassStateChanged(nearlyExpired, isNearlyDue));
            row.itemProperty().addListener((obs, oldBill, newBill) -> {
                nearlyDueProperty.unbind();
                if (newBill == null) {
                    nearlyDueProperty.set(false);
                } else {
                    nearlyDueProperty.bind(Bindings.createBooleanBinding(() -> 
                            newBill.getExpirationDate().minusDays(7).isBefore(newBill.getPaymentDate()),
                            newBill.expirationDateProperty(), newBill.paymentDateProperty()));
                }
            });

            return row ;
        });


        TableColumn<Bill, LocalDate> paymentDateCol = column("Payment Date", Bill::paymentDateProperty);
        table.getColumns().add(paymentDateCol);

        LocalDateStringConverter converter = new LocalDateStringConverter();
        Callback<TableColumn<Bill, LocalDate>, TableCell<Bill, LocalDate>> 
            defaultCellFactory = TextFieldTableCell.forTableColumn(converter);

        paymentDateCol.setCellFactory(defaultCellFactory);

        TableColumn<Bill, LocalDate> expirationDateCol = column("Expiration Date", Bill::expirationDateProperty);
        table.getColumns().add(expirationDateCol);

        expirationDateCol.setCellFactory(tc -> {
            TableCell<Bill, LocalDate> cell = defaultCellFactory.call(tc);
            cell.getStyleClass().add("expiration-cell");
            return cell ;
        });

        Random rng = new Random();
        for (int i = 1; i <= 20 ; i++) {
            LocalDate now = LocalDate.now();
            LocalDate payment = now.plusDays(rng.nextInt(5));
            LocalDate expiration = payment.plusDays(rng.nextInt(14));
            table.getItems().add(new Bill(payment, expiration));
        }

        Scene scene = new Scene(table);
        scene.getStylesheets().add("payment-table.css");

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private static <S,T> TableColumn<S,T> column(String title, Function<S,Property<T>> property) {
        TableColumn<S,T> col = new TableColumn<>(title);
        col.setCellValueFactory(cellData -> property.apply(cellData.getValue()));
        return col ;
    }

    public static class Bill {
        private final ObjectProperty<LocalDate> paymentDate = new SimpleObjectProperty<>();
        private final ObjectProperty<LocalDate> expirationDate = new SimpleObjectProperty<>();

        // other properties...

        public Bill(LocalDate paymentDate, LocalDate expirationDate) {
            setPaymentDate(paymentDate);
            setExpirationDate(expirationDate);
        }

        public final ObjectProperty<LocalDate> paymentDateProperty() {
            return this.paymentDate;
        }


        public final java.time.LocalDate getPaymentDate() {
            return this.paymentDateProperty().get();
        }


        public final void setPaymentDate(final java.time.LocalDate paymentDate) {
            this.paymentDateProperty().set(paymentDate);
        }


        public final ObjectProperty<LocalDate> expirationDateProperty() {
            return this.expirationDate;
        }


        public final java.time.LocalDate getExpirationDate() {
            return this.expirationDateProperty().get();
        }


        public final void setExpirationDate(final java.time.LocalDate expirationDate) {
            this.expirationDateProperty().set(expirationDate);
        }

    }

    public static void main(String[] args) {
        launch(args);
    }
}

with the stylesheet above in payment-table.css.使用上面payment-table.css 中的样式表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 没有FXML的情况下如何更改按钮的背景色? #JAVAFX - How can I change the background color in the button without FXML? #JAVAFX 如何检查 javafx tableview 中的编辑单元格是否正确,如果不正确:如何将单元格值设置回来? - How can I check if an edit cell in javafx tableview is correct, and if it isn't: how can I set the cell value back? 如何更改 java swing 中网格单元格的颜色? - How do I change the color of a grid cell in java swing? 如何根据表格中的数据修改合适的单元格颜色(在Matlab中)? - How to modify uitable cell color according to data in table (in Matlab)? 表格单元格中的JavaFX颜色选择器自定义颜色 - JavaFX Color Picker Custom Color In Table Cell JavaFX-更改表格视图单元格中的文本 - JavaFX - Change text in tableview cell 根据手机自动更改UI - Change UI automatically according to the cell phone 每当上一行中的任何单元格被填充时,如何使DataGridView不产生新行? - How can I make a DataGridView not to produce a new row whenever any of the cell in the preceeding row is filled up? JavaFX列/单元格值未更新 - JavaFX column/cell-value not updating 如何根据单元格的值为jtable的单元格着色 - How to color cells of jtable depending on cell's value
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM