JavaFX TableView Zelle markieren

ProChris

Mitglied
Hallo zusammen,

ich habe folgende Tabelle als TableView implementiert und mit folgenden Daten gefüllt:

IDVonNachEntfernung
1HamburgBerlin200
2BerlinHamburg200
3MünchenBerlin

Ich möchte folgende Logik implementieren:

  • Wenn der Text in Zeile 1 aus Spalte "NACH" gleich dem Text in Zeile 2 aus Spalte "VON" ist, dann soll der Hintergrund von Zeile 1 in Spalte "NACH" grün und der Hintergrund von Zeile 2 in Spalte "VON" auch grün gesetzt werden.
Hat jemand eine Idee, wie man so etwas umsetzen kann? Im Internet finde ich immer nur Anleitungen, um eine ganze Row einzufärben. Ich möchte nur eine einzelne Zelle einfärben. Aber auch nur dann, wenn die Zelle aus der nächsten Zeile in einer anderen Spalte den gleichen Wert hat.

Viele Grüße

ProChris
 
So scheint mir das zu funktionieren:
Java:
import java.util.Objects;
import java.util.function.Predicate;

import javafx.application.Application;
import javafx.beans.binding.*;
import javafx.collections.*;
import javafx.collections.transformation.SortedList;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

public class Test extends Application {

    class Connection {
        int id;
        String departure;
        String arrival;
        Integer distance;

        public Connection(int id, String departure, String arrival) {
            this(id, departure, arrival, null);
        }

        public Connection(int id, String departure, String arrival, Integer dist) {
            this.id = id;
            this.departure = departure;
            this.arrival = arrival;
            this.distance = dist;
        }
    }

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

    @Override
    public void start(Stage primaryStage) {
        TableColumn<Connection, Number> idCol = new TableColumn<>("ID");
        TableColumn<Connection, String> depCol = new TableColumn<>("Von");
        TableColumn<Connection, String> arrCol = new TableColumn<>("Nach");
        TableColumn<Connection, Number> distCol = new TableColumn<>("Entfernung");

        idCol.setCellValueFactory(cdf ->
                Bindings.createIntegerBinding(() -> cdf.getValue().id));
        depCol.setCellValueFactory(cdf ->
                Bindings.createStringBinding(() -> cdf.getValue().departure));
        arrCol.setCellValueFactory(cdf -> 
                Bindings.createStringBinding(() -> cdf.getValue().arrival));
        distCol.setCellValueFactory(cdf -> 
                Bindings.createIntegerBinding(() -> cdf.getValue().distance));

        depCol.setCellFactory(col -> new StyledCell<Connection, String>(
                    "-fx-background-color: lightgreen;", cell -> {
            TableView<Connection> table = cell.getTableView();
            SortedList<Connection> sl = (SortedList<Connection>)table.getItems();
            int rowIndex = sl.getSourceIndex(cell.getTableRow().getIndex());
            
            boolean result = rowIndex > 0 && 
                Objects.equals(sl.getSource().get(rowIndex-1).arrival, 
                               sl.getSource().get(rowIndex).departure);

            return result;

        }));
        arrCol.setCellFactory(col -> new StyledCell<Connection, String>(
                    "-fx-background-color: lightgreen;", cell -> {
            TableView<Connection> table = cell.getTableView();
            SortedList<Connection> sl = (SortedList<Connection>)table.getItems();
            int rowIndex = sl.getSourceIndex(cell.getTableRow().getIndex());
            
            boolean result = rowIndex + 1 < sl.size() && 
                Objects.equals(sl.getSource().get(rowIndex).arrival, 
                               sl.getSource().get(rowIndex+1).departure);
            return result;

        }));

        TableView<Connection> connectionTable = new TableView<>();
        connectionTable.getColumns().addAll(idCol, depCol, arrCol, distCol);
    

        ObservableList<Connection> connections = FXCollections.observableArrayList(
            new Connection(1, "Hamburg", "Berlin", 200),
            new Connection(2, "Berlin", "Hamburg", 200),
            new Connection(3, "München", "Berlin", 0)
        );

        SortedList<Connection> sl = new SortedList<>(connections);
        sl.comparatorProperty().bind(connectionTable.comparatorProperty());
        connectionTable.setItems(sl);


        primaryStage.setTitle("javafx-skeleton");

        BorderPane panel = new BorderPane();
        panel.setCenter(connectionTable);

        Scene scene = new Scene(panel, 300, 200);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    private static class StyledCell<S,T> extends TableCell<S,T> {
        private Predicate<TableCell<S,T>> predicate;
        private String style;

        public StyledCell(String style, Predicate<TableCell<S,T>> predicate) {
            this.predicate = predicate;
            this.style = style;
        }

        @Override
        public void updateItem(T value, boolean empty) {
            super.updateItem(value, empty);
            setText(value == null || empty ? "" : value.toString());
            setStyle("-fx-background-color: null;");
            if (!empty && getTableRow() != null) {
                if (predicate.test(this)) {
                    setStyle(style);
                }
            }
        }
    }
}
 
Ich verstehe folgende Codezeilen nicht so ganz:

Code:
TableColumn<Connection, Number> idCol = new TableColumn<>("ID");
idCol.setCellValueFactory(cdf ->
                Bindings.createIntegerBinding(() -> cdf.getValue().id));

Warum funktioniert das und warum funktioniert das folgende nicht?

Code:
TableColumn<Connection, Integer> idCol = new TableColumn<>("ID");
idCol.setCellValueFactory(cdf ->
                Bindings.createIntegerBinding(() -> cdf.getValue().id));
 
Die cell value factory ist ein Callback, der als Rückgabewert eine ObservableValue erwartet. Das IntegerBinding implementiert ObservableValue<Number> und nicht ObservableValue<Integer>.
 

Zurück
Oben