2016-05-02 13 views
0

Ich habe die letzten Stunden online gesucht und versucht, diese Funktion ohne Erfolg zu implementieren.Markieren Sie TableView-Zeilen in JavaFX, wenn die Zeitzelle hinter der aktuellen Zeit liegt

Ich habe eine TableView mit verschiedenen Spalten, von denen eine ist ein String-Feld, das eine Zeit enthält. Ich möchte alle Zeilen hervorheben, die einen timeCol Wert haben, der später als die aktuelle Zeit ist.

Dies muss alle 5 Minuten überprüft werden und die Tabelle entsprechend hervorheben. Ich gehe davon aus, dass dies auf einem Hintergrund-Thread ausgeführt werden muss, aber ich habe Erfahrung mit Nebenläufigkeit.

Tableview Inhalt

@FXML 
private TableView<BookingImpl> bookingTableView; 
@FXML 
private TableColumn<BookingImpl, String> timeCol; 
@FXML 
private TableColumn<BookingImpl, String> nameCol; 
@FXML 
private TableColumn<BookingImpl, String> pickUpCol; 
@FXML 
private TableColumn<BookingImpl, String> dropOffCol; 
@FXML 
private TableColumn<BookingImpl, String> commentCol; 
@FXML 
private TableColumn<BookingImpl, String> priceCol; 

ich diesen Beitrag JavaFX tableview colors gesehen haben, die wie folgt aussieht, was ich erreichen will, die Highlight-Farbe palevioletred werden muss.

Jede Anleitung wird sehr geschätzt.

UPDATE - James_D Lösung

Ich habe dies angepasst meine Anwendung zu passen, es jedoch nur die späten Buchungen auf Eingang unterstreicht, dh wenn ich eine Buchung 1 Minute von jetzt eingeben und warte, es wird nicht markieren . Ich habe die FXML-Implementierung von Spalten deaktiviert, würde sie aber lieber verwenden.

Ich verweise diese neue Klasse von meiner Hauptsteuerungsklasse wie folgt;

TableRowController rowController = new TableRowController(); 
rowController.start(bookingTableView); 

TableRowController

Paket Controllers;

import Model.BookingImpl; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.Property; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.css.PseudoClass; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableRow; 
import javafx.scene.control.TableView; 

import java.time.LocalTime; 
import java.util.function.Function; 

public class TableRowController{ 

private final PseudoClass future = PseudoClass.getPseudoClass("future"); 

public void start(TableView table){ 
    ObjectProperty<LocalTime> now = new SimpleObjectProperty<>(LocalTime.now()); 
    table.setRowFactory(tv -> { 
     TableRow<BookingImpl> row = new TableRow<>(); 
     ChangeListener<LocalTime> listener = (obs, oldTime, newTime) -> updateRow(row, now.get()); 
     now.addListener(listener); 
     row.itemProperty().addListener((obs, oldItem, newItem) -> { 
      if (oldItem != null) { 
       oldItem.getTimeProperty().removeListener(listener); 
      } 
      if (newItem != null) { 
       newItem.getTimeProperty().addListener(listener); 
      } 
      updateRow(row, now.get()); 
     }); 
     return row ; 
    }); 

    configureTable(table); 
} 

public void updateRow(TableRow<BookingImpl> row, LocalTime now) { 
    boolean isFuture = false ; 
    if (row.getItem() != null) { 
     isFuture = row.getItem().getTime().isBefore(now); 
    } 
    row.pseudoClassStateChanged(future, isFuture); 
} 


private void configureTable(TableView<BookingImpl> table) { 
    table.getColumns().add(column("Time", (Function<BookingImpl, Property<LocalTime>>) (t) -> t.getTimeProperty())); 
    table.getColumns().add(column("Name", (Function<BookingImpl, Property<String>>) (t) -> new SimpleStringProperty(t.getClientName()))); 
    table.getColumns().add(column("Pickup", (Function<BookingImpl, Property<String>>) (t) -> new SimpleStringProperty(t.getPickUpAddress()))); 
    table.getColumns().add(column("Dropoff", (Function<BookingImpl, Property<String>>) (t) -> new SimpleStringProperty(t.getDropOffAddress()))); 
    table.getColumns().add(column("Comment", (Function<BookingImpl, Property<String>>) (t) -> new SimpleStringProperty(t.getComments()))); 
    table.getColumns().add(column("Price", (Function<BookingImpl, Property<String>>) (t) -> new SimpleStringProperty(t.getFormattedPrice()))); 
    table.setItems(ObservableLists.bookingsList); 
} 

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

} 

BookingImpl Klasse

public class BookingImpl implements Booking { 
public static int bookingNumberCounter = 1001; 
private final int bookingNumber; 
private Account account; 
private String vehicleType; 
private String noPassengers; 
private LocalDate date; 
private ObjectProperty<LocalTime> time = new SimpleObjectProperty<>(); 
private String pickUpAddress; 
private String dropOffAddress; 
private String clientName; 
private String clientTel; 
private String clientEmail; 
private String comments; 
private double price; 
private boolean completed = false; 
private Driver driver; 

public BookingImpl(Account account){ 
    this.bookingNumber = bookingNumberCounter; 
    bookingNumberCounter++; 
    Archive.allBookings.add(this); 
    Archive.incompleteBookings.add(this); 
    ObservableLists.bookingsList.clear(); 
    ObservableLists.bookingsList.addAll(Archive.incompleteBookings); 
    account.newBooking(this); 
} 


@Override 
public void deleteBooking() { 
    account.deleteBooking(this); 
    Archive.allBookings.remove(this); 
} 

public int getBookingNumber() { 
    return bookingNumber; 
} 

public Account getAccount() { 
    return account; 
} 

public void setAccount(Account account) { 
    this.account = account; 
} 

public String getVehicleType() { 
    return vehicleType; 
} 

public void setVehicleType(String vehicleType) { 
    this.vehicleType = vehicleType; 
} 

public String getNoPassengers() { 
    return noPassengers; 
} 

public void setNoPassengers(String noPassengers) { 
    this.noPassengers = noPassengers; 
} 

public String getDate() { 
    return new SimpleDateFormat("dd/MM/yyyy").format(date); 
} 

public void setDate(LocalDate date) { 
    this.date = date; 
} 

public ObjectProperty<LocalTime> getTimeProperty() { 
    return time; 
} 

public LocalTime getTime() { 
    return this.getTimeProperty().get(); 
} 

public void setTime(LocalTime time) {this.time.set(time);} 

public String getPickUpAddress() { 
    return pickUpAddress; 
} 

public void setPickUpAddress(String pickUpAddress) { 
    this.pickUpAddress = pickUpAddress; 
} 

public String getDropOffAddress() { 
    return dropOffAddress; 
} 

public void setDropOffAddress(String dropOffAddress) { 
    this.dropOffAddress = dropOffAddress; 
} 

public String getClientName() { 
    return clientName; 
} 

public void setClientName(String clientName) { 
    this.clientName = clientName; 
} 

public String getClientTel() { 
    return clientTel; 
} 

public void setClientTel(String clientTel) { 
    this.clientTel = clientTel; 
} 

public String getClientEmail() { 
    return clientEmail; 
} 

public void setClientEmail(String clientEmail) { 
    this.clientEmail = clientEmail; 
} 

public String getComments() { 
    return comments; 
} 

public void setComments(String comments) { 
    this.comments = comments; 
} 

public double getPrice() { 
    return price; 
} 

public String getFormattedPrice() { 
    DecimalFormat df = new DecimalFormat("#.00"); 
    return "£"+df.format(this.price); 
} 
public void setPrice(double price) { 
    this.price = price; 
} 

public boolean isCompleted() { 
    return completed; 
} 

public void setCompleted(boolean completed) { 
    this.completed = completed; 
} 

public Driver getDriver() { 
    return driver; 
} 

public void setDriver(Driver driver) { 
    this.driver = driver; 
} 
} 
+1

"A' String' Feld, das eine Zeit hält ..." wäre nicht macht es mehr Sinn, eine 'LocalTime' anstatt einer' String' zu verwenden? –

+0

Hallo, dies kann zu "LocalTime" ohne ein Problem geändert werden. Type ist eigentlich "Date", wird aber in einem String-Feld gespeichert. – J2FX

+0

Ihre Zellenwertfabriken sehen falsch aus. Verwendet Ihre 'BookingImpl'-Klasse JavaFX-Eigenschaften? Wo rufst du auch 'start()'? –

Antwort

0

Ich würde diesen Ansatz wie folgt:

Verwenden Sie ein rowFactory auf dem Tisch. Die von Ihnen erstellte Zeile wird die Eigenschaft time des aktuellen Elements beobachten und eine CSS PseudoClass aktualisieren, wenn sich diese ändert. Sie brauchen auch die Zeile, um die aktuelle Uhrzeit zu beobachten: Dazu erstellen Sie eine ObjectProperty<LocalTime> und aktualisieren sie von einer AnimationTimer.

Der Vorteil der Verwendung einer CSS PseudoClass besteht darin, dass Sie den Stil in einer externen CSS-Datei definieren können. Hier

ein Beispiel:

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

import javafx.animation.AnimationTimer; 
import javafx.application.Application; 
import javafx.beans.property.ObjectProperty; 
import javafx.beans.property.Property; 
import javafx.beans.property.SimpleObjectProperty; 
import javafx.beans.property.SimpleStringProperty; 
import javafx.beans.property.StringProperty; 
import javafx.beans.value.ChangeListener; 
import javafx.css.PseudoClass; 
import javafx.scene.Scene; 
import javafx.scene.control.Label; 
import javafx.scene.control.TableColumn; 
import javafx.scene.control.TableRow; 
import javafx.scene.control.TableView; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 

public class HighlightFutureItems extends Application { 

    private final PseudoClass future = PseudoClass.getPseudoClass("future"); 

    @Override 
    public void start(Stage primaryStage) { 
     TableView<Item> table = new TableView<>(); 

     ObjectProperty<LocalTime> now = new SimpleObjectProperty<>(LocalTime.now()); 

     startClock(now); 

     table.setRowFactory(tv -> { 
      TableRow<Item> row = new TableRow<>(); 
      ChangeListener<LocalTime> listener = (obs, oldTime, newTime) -> updateRow(row, now.get()); 
      now.addListener(listener); 
      row.itemProperty().addListener((obs, oldItem, newItem) -> { 
       if (oldItem != null) { 
        oldItem.timeProperty().removeListener(listener); 
       } 
       if (newItem != null) { 
        newItem.timeProperty().addListener(listener); 
       } 
       updateRow(row, now.get()); 
      }); 
      return row ; 
     }); 

     configureTable(table); 

     BorderPane root = new BorderPane(table); 
     Label clock = new Label(); 
     root.setTop(clock); 

     clock.textProperty().bind(now.asString()); 

     Scene scene = new Scene(root, 600, 600); 
     scene.getStylesheets().add("future-highlighting-table.css"); 
     primaryStage.setScene(scene); 
     primaryStage.show(); 
    } 

    private void updateRow(TableRow<Item> row, LocalTime now) { 
     boolean isFuture = false ; 
     if (row.getItem() != null) { 
      isFuture = row.getItem().getTime().isAfter(now); 
     } 
     row.pseudoClassStateChanged(future, isFuture); 
    } 

    private void startClock(ObjectProperty<LocalTime> clock) { 
     new AnimationTimer() { 
      @Override 
      public void handle(long timestamp) { 
       clock.set(LocalTime.now()); 
      } 
     }.start(); 
    } 

    private void configureTable(TableView<Item> table) { 
     table.getColumns().add(column("Item", Item::nameProperty)); 
     table.getColumns().add(column("Time", Item::timeProperty)); 

     Random rng = new Random(); 
     LocalTime now = LocalTime.now(); 
     for (int i = 1 ; i <= 50 ; i++) { 
      Item item = new Item("Item "+i, now.plusSeconds(rng.nextInt(120) - 60)); 
      table.getItems().add(item); 
     } 
    } 

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

    public static class Item { 
     private final StringProperty name = new SimpleStringProperty(); 
     private final ObjectProperty<LocalTime> time = new SimpleObjectProperty<>(); 

     public Item(String name, LocalTime time) { 
      setName(name); 
      setTime(time); 
     } 

     public final StringProperty nameProperty() { 
      return this.name; 
     } 


     public final String getName() { 
      return this.nameProperty().get(); 
     } 


     public final void setName(final String name) { 
      this.nameProperty().set(name); 
     } 


     public final ObjectProperty<LocalTime> timeProperty() { 
      return this.time; 
     } 


     public final LocalTime getTime() { 
      return this.timeProperty().get(); 
     } 


     public final void setTime(final LocalTime time) { 
      this.timeProperty().set(time); 
     } 



    } 

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

Die CSS-Datei (future-highlighting-table.css") kann so einfach wie

.table-row-cell:future { 
    -fx-background: palevioletred; 
} 
+0

Ausgezeichnetes Beispiel! das wird gut für mich funktionieren Ich schätze deine Antwort wirklich @James_D – J2FX

+0

Ich bemerkte, dass du ' 'als Tabellentyp benutzt hast, ich habe versucht, dies in' 'umzuwandeln und den Code zu refaktorieren, aber ich habe Probleme damit bekommen . Muss ich '' für das TableView verwenden? – J2FX

+0

Nein, natürlich nicht. Element ist nur der Name der Klasse, die ich im Beispiel definiert habe. –

Verwandte Themen