2016-03-28 4 views
-1

私のアプリケーションにはTableViewがあります。 2つの列は支払い日と有効期限です。各行で、同じ行の支払い日付セルの値に基づいて、個々の有効期限セルの背景色を変更したいとします。私の最大の試みはここにあります:JavaFX 8では、同じ行の別のセルの値に従って、セルの背景色を変更するにはどうすればいいですか?

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

    ... 
} 

アプリを実行するために必要なものはすべてhereです。

より具体的には、有効期限セルの背景色を設定しているときは、同じ行の別のセルを参照する方法を見つけることができません。

+0

コードを減らして、ダウンロードしなくても実行できるようにすることはできますか? (言い換えると、[MCVE]を提供します)実際の問題を示すために2つの列が必要です。モデルクラスには2つのプロパティがあります。 –

+0

完了。私は関連する部分だけを残しました。 – coderodde

+0

今私は実際の要件について混乱しています。どのような細胞の色を決定する必要がありますか? 'onCommitEdit'の場所はあなたがしようとしているところであれば、それを行う場所ではありません。 –

答えて

0

これを行う最もきれいな方法は、おそらく、テーブル行のスタイルクラスまたは擬似クラスを変更する行ファクトリを使用することです。次に、セルに固定されたスタイルクラスを設定します。

私の例では、従来のDateタイプの代わりにLocalDateを使用しています。あなたは

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

ような何かを行うことができますし、もちろん、あなたが定義することができ、その後、列自体のために、あなただけの

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

を必要とし、最終的にあなたが

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

で外部スタイルシートを添付することができますあなたがここで好きな方法でスタイルを整えます。支払い-table.css上記のスタイルシートと

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

はここで完全な例です。