JavaFX Zwei Dinge in einer CellFactory erledigen

VictorRomeo

Mitglied
Hallo Forum,

ich stehe etwas auf dem Schlauch im Zusammenhang mit einem TableView. Ich habe ein TableView, welches ich über eine ObservableList mit Werten befülle. Das klappt soweit auch wie gewünscht. Nun möchte ich bei Doppelklick auf eine Zeile eine Referenz auf das unterliegende Objekt bekommen. Also ne CellFactory bemüht, wie folgt:

Java:
TableView.setRowFactory((row) -> {
  TableRow<Person> row = new TableRow<>();
  row.setOnMouseClicked(event -> {
    if (event.getClickCount() == 2 && (!row.isEmpty())) {
      Person rowData = row.getItem();
      System.out.println(rowData);
    }
  });
  return row;
});

nun möchte ich aber die Zeilen noch in Abhängikeit Ihres Inhaltes in einer anderen Farbe einfärben. Das funktioniert auch gut, wenn ich eine Factory wie folgt mache:

Java:
TableView.setRowFactory((row) -> new TableRow<Person>() {

@Override
public void updateItem(Person person, boolean empty) {
	super.updateItem(person, empty);

	switch (person.getPersonStatus()) {
	  case ST:
	    setStyle("-fx-control-inner-background: " + StatusFarben.DIES_LIGHT.getFarbwert() + "; -fx-text-fill: #fff;");
		break;
	  case CD:
	    setStyle("-fx-control-inner-background: " + StatusFarben.DAS_LIGHT.getFarbwert() + "; -fx-text-fill: #fff;");
		break;
	}
}

Nur wie bekomme ich das jetzt beides unter einen Hut? Ehrlich gesagt verstehe ich den ganzen Callback und Lambda-Kram auch noch nicht wirklich ... die Schnippsel sind angepassst aus anderen Projekten ..... 😳

für sachdienliche Hinweise oder die Lösung dankt,
VR
 
Zuletzt bearbeitet:
Wenn du den "Lambdakram" nicht verstehst, dann verwende ihn nicht!

Zweiter Punkt: Callbacks sollte man unbedingt verstehen, denn jeder Listener funktioniert so!

Ich hätte das dann einfach zusammegefügt mit:

Java:
TableView.setRowFactory((row) -> {
  TableRow<Person> row = new TableRow<Person>() {
    @Override
    public void updateItem(Person person, boolean empty) {
      super.updateItem(person, empty);
      switch (person.getPersonStatus()) {
        case ST:
          setStyle("-fx-control-inner-background: "
                  + StatusFarben.DIES_LIGHT.getFarbwert()
                  + "; -fx-text-fill: #fff;");
          break;
        case CD:
          setStyle("-fx-control-inner-background: "
                  + StatusFarben.DAS_LIGHT.getFarbwert()
                  + "; -fx-text-fill: #fff;");
          break;
      }
    }
  }
  row.setOnMouseClicked(event -> {
    if (event.getClickCount() == 2 && (!row.isEmpty())) {
      Person rowData = row.getItem();
      System.out.println(rowData);
    }
  });
  return row;
}
 
Hallo Flown,

Danke für deine schnelle Antwort.

Bezüglich Lamdas und Callbacks verstehe ich es nur begrenzt - ich arbeite noch an dem "Aha"-Effekt ... mir fehlt irgendwie noch der richtige Text (Link) dazu.

Zu meinem Problem von oben: So wie du es jetzt gemacht hast, hatte ich es auch schon gedacht . allerdings mosert dann Eclipse:

(Multiple markers at this line
- Syntax error, insert ";" to complete Statement
- Syntax error, insert ")" to complete MethodInvocation)

Ich komme da nicht weiter - wieso ist das Statement falsch?
 
Keine Ahnung warum das bei dir nicht funktioniert, aber mit dem Codeschnipsel, dass du gelieft hast, kann man nicht mehr anfangen.
 
Mir geht es bei der Frage auch nicht unbedingt um den Codeschnippsel. Ich hatte mir eventuell einen Hinweis auf einen anderen Ansatz erhofft. Es muss doch möglich sein, die Methode UpdateItem zu überschreiben und der Reihe dabei einen Listener anzuhängen?!
 
Ahja ich bin gerade über das hier gestoßen, die selbe Frage auf SO und du hast die selbe Antwort auch nochmal von einen anderen bekommen.
 
Ahja ich bin gerade über das hier gestoßen, die selbe Frage auf SO und du hast die selbe Antwort auch nochmal von einen anderen bekommen.

Ist richtig. Nicht das ich dir nicht geglaubt hätte - habs nur nicht hinbekommen. Dann bin ich wohl zu dämlich ... also nochmal drüber brüten. Vielen Dank übrigens für deinen obigen Hinweis mit den Callbacks, welche du mit Listenern in Verbindung gebracht hast. Hat mir schon wieder weitergeholfen ....
 
So hier ein Beispiel:

Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="200" prefWidth="320" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8" fx:controller="tableapp.FXMLDocumentController">
   <children>
      <TableView fx:id="tableView" layoutX="60.0" prefHeight="200.0" prefWidth="320.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
        <columns>
          <TableColumn fx:id="numberCol" prefWidth="75.0" text="Numbers" />
        </columns>
         <columnResizePolicy>
            <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
         </columnResizePolicy>
      </TableView>
   </children>
</AnchorPane>

Java:
package tableapp;

import java.util.stream.Collectors;
import java.util.stream.IntStream;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableRow;
import javafx.scene.control.TableView;
import javafx.scene.input.MouseEvent;

public class FXMLDocumentController {

  @FXML
  private TableView<Integer> tableView;
  @FXML
  private TableColumn<Integer, Integer> numberCol;

  private ObservableList<Integer> numbers;

  @FXML
  public void initialize() {
    numbers = FXCollections.observableArrayList(IntStream.range(0, 100).boxed().collect(Collectors.toList()));
    tableView.setItems(numbers);
    numberCol.setCellValueFactory((TableColumn.CellDataFeatures<Integer, Integer> param) -> new SimpleObjectProperty<>(param.getValue()));
    tableView.setRowFactory((TableView<Integer> param) -> {
      TableRow<Integer> row = new TableRow<Integer>() {
        @Override
        protected void updateItem(Integer item, boolean empty) {
          super.updateItem(item, empty);
          if (!empty) {
            if (item % 2 == 0) {
              setStyle("-fx-control-inner-background: #00f200;");
            } else {
              setStyle("-fx-control-inner-background: #0000f2;");
            }
          }
        }
      };
      row.setOnMouseClicked((MouseEvent event) -> {
        if (event.getClickCount() == 2 && (!row.isEmpty())) {
          int rowData = row.getItem();
          System.out.println(rowData);
        }
      });
      return row;
    });
  }
}

Java:
package tableapp;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class TableApp extends Application {

  @Override
  public void start(Stage stage) throws Exception {
    Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

    Scene scene = new Scene(root);

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

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

}
 
Ok, habs jetzt hinbekommen. Danke für das Beispiel. Anhand dessen bin ich auch nochmal bei den Callbacks weitergekommen und habe mich mal mit CellDataFeatures beschäftigt. Das brachte die Erleuchtung in diesem Problem. Glaube ich verstehe jetzt auch die CallBacks wenn ich sie sehe - mal sehen ob ich die dann auch selber hinbekomme. Danke.
 

Zurück
Oben