javafx
Tabellenansicht
Suche…
Beispiel TableView mit 2 Spalten
Tabellenelement
Die folgende Klasse enthält 2 Eigenschaften, einen Namen ( String
) und die Größe ( double
). Beide Eigenschaften sind in JavaFX-Eigenschaften eingeschlossen, damit TableView
Änderungen beobachten kann.
import javafx.beans.property.DoubleProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
public class Person {
public Person(String name, double size) {
this.size = new SimpleDoubleProperty(this, "size", size);
this.name = new SimpleStringProperty(this, "name", name);
}
private final StringProperty name;
private final DoubleProperty size;
public final String getName() {
return this.name.get();
}
public final void setName(String value) {
this.name.set(value);
}
public final StringProperty nameProperty() {
return this.name;
}
public final double getSize() {
return this.size.get();
}
public final void setSize(double value) {
this.size.set(value);
}
public final DoubleProperty sizeProperty() {
return this.size;
}
}
Beispielanwendung
Diese Anwendung zeigt eine TableView
mit 2 Spalten. eine für den Namen und eine für die Größe einer Person
. Wenn Sie eine der Person
TextField
die Daten TextField
unterhalb der TableView
und der Benutzer kann die Daten bearbeiten. Beachten Sie, dass die TableView
automatisch aktualisiert wird, sobald die Bearbeitung TableView
ist.
Jeder für jede TableColumn
, die der TableView
hinzugefügt wird, TableView
eine cellValueFactory
zugewiesen. Diese Factory ist für die Konvertierung von Tabellenelementen ( Person
) in ObservableValue
Werte verantwortlich, die den Wert enthalten, der in der Tabellenzelle angezeigt werden soll. TableView
kann TableView
Änderungen für diesen Wert TableView
.
import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.scene.control.TextFormatter;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
import javafx.util.StringConverter;
public class TableSample extends Application {
@Override
public void start(Stage primaryStage) {
// data for the tableview. modifying this list automatically updates the tableview
ObservableList<Person> data = FXCollections.observableArrayList(
new Person("John Doe", 1.75),
new Person("Mary Miller", 1.70),
new Person("Frank Smith", 1.80),
new Person("Charlotte Hoffman", 1.80)
);
TableView<Person> tableView = new TableView<>(data);
// table column for the name of the person
TableColumn<Person, String> nameColumn = new TableColumn<>("Name");
nameColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person, String>, ObservableValue<String>>() {
@Override
public ObservableValue<String> call(TableColumn.CellDataFeatures<Person, String> param) {
return param.getValue().nameProperty();
}
});
// column for the size of the person
TableColumn<Person, Number> sizeColumn = new TableColumn<>("Size");
sizeColumn.setCellValueFactory(new Callback<TableColumn.CellDataFeatures<Person, Number>, ObservableValue<Number>>() {
@Override
public ObservableValue<Number> call(TableColumn.CellDataFeatures<Person, Number> param) {
return param.getValue().sizeProperty();
}
});
// add columns to tableview
tableView.getColumns().addAll(nameColumn, sizeColumn);
TextField name = new TextField();
TextField size = new TextField();
// convert input from textfield to double
TextFormatter<Double> sizeFormatter = new TextFormatter<Double>(new StringConverter<Double>() {
@Override
public String toString(Double object) {
return object == null ? "" : object.toString();
}
@Override
public Double fromString(String string) {
if (string == null || string.isEmpty()) {
return null;
} else {
try {
double val = Double.parseDouble(string);
return val < 0 ? null : val;
} catch (NumberFormatException ex) {
return null;
}
}
}
});
size.setTextFormatter(sizeFormatter);
Button commit = new Button("Change Item");
commit.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
Person p = tableView.getSelectionModel().getSelectedItem();
p.setName(name.getText());
Double value = sizeFormatter.getValue();
p.setSize(value == null ? -1d : value);
}
});
// listen for changes in the selection to update the data in the textfields
tableView.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<Person>() {
@Override
public void changed(ObservableValue<? extends Person> observable, Person oldValue, Person newValue) {
commit.setDisable(newValue == null);
if (newValue != null) {
sizeFormatter.setValue(newValue.getSize());
name.setText(newValue.getName());
}
}
});
HBox editors = new HBox(5, new Label("Name:"), name, new Label("Size: "), size, commit);
VBox root = new VBox(10, tableView, editors);
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
PropertyValueFactory
PropertyValueFactory
kann als cellValueFactory
in einer TableColumn
. Es verwendet Reflektion, um auf Methoden zuzugreifen, die einem bestimmten Muster entsprechen, um die Daten von einem TableView
Element TableView
:
Beispiel
TableColumn<Person, String> nameColumn = ...
PropertyValueFactory<Person, String> valueFactory = new PropertyValueFactory<>("name");
nameColumn.setCellValueFactory(valueFactory);
Der Name der Methode, die zum Abrufen der Daten verwendet wird, hängt vom Konstruktorparameter für PropertyValueFactory
.
- Eigenschaftsmethode: Es wird erwartet, dass diese Art von Methode einen
ObservableValue
, der die Daten enthält. Änderungen können beobachtet werden. Sie müssen mit der<constructor parameter>Property
pattern<constructor parameter>Property
übereinstimmen und keine Parameter übernehmen. - Getter-Methode: Diese Art von Methode erwartet, dass der Wert direkt zurückgegeben wird (
String
im obigen Beispiel). Der Methodenname muss mit dem Muster übereinstimmen,get<Constructor parameter>
. Beachten Sie, dass hier<Constructor parameter>
mit einem Großbuchstaben beginnt. Diese Methode sollte keine Parameter annehmen.
Beispielnamen der Methoden
Konstruktorparameter (ohne Anführungszeichen) | Name der Eigenschaftsmethode | Name der Getter-Methode |
---|---|---|
foo | fooProperty | getFoo |
fooBar | fooBarProperty | getFooBar |
XYZ | XYZProperty | getXYZ |
listIndex | listIndexProperty | getListIndex |
ein Wert | aValueProperty | getAValue |
Anpassen der TableCell-Ansicht je nach Artikel
Manchmal sollte eine Spalte einen anderen Inhalt als nur den toString
Wert des toString
anzeigen. In diesem Fall wird die TableCell
s durch die erstellte cellFactory
des TableColumn
wird angepasst , das Layout auf dem Elemente basiert zu ändern.
Wichtiger Hinweis: TableView
erstellt nur die TableCell
, die in der Benutzeroberfläche angezeigt werden. Die Elemente in den Zellen können sich ändern oder sogar leer werden. Der Programmierer muss darauf achten, alle Änderungen an der TableCell
rückgängig zu machen, die TableCell
wurden, als ein Element hinzugefügt wurde, wenn es entfernt wurde. Andernfalls wird der Inhalt möglicherweise immer noch in einer Zelle angezeigt, in der "es nicht gehört".
In der folgenden Beispieleinstellung führt ein Element dazu, dass der Text gesetzt wird und das Bild in der ImageView
angezeigt ImageView
:
image.setImage(item.getEmoji());
setText(item.getValue());
Wenn das Element wird null
oder die Zelle leer wird, werden diese Änderungen rückgängig gemacht , indem die Werte wieder auf Einstellung null
:
setText(null);
image.setImage(null);
Das folgende Beispiel zeigt ein Emoji zusätzlich zu Text in einer TableCell
.
Die updateItem
Methode wird bei jeder updateItem
des Elements einer Cell
aufgerufen. Wenn Sie diese Methode überschreiben, können Sie auf Änderungen reagieren und das Aussehen der Zelle anpassen. Das Hinzufügen eines Listeners zu itemProperty()
einer Zelle wäre eine Alternative, in vielen Fällen wird TableCell
jedoch erweitert.
Gegenstandsart
import javafx.scene.image.Image;
// enum providing image and text for certain feelings
public enum Feeling {
HAPPY("happy", "https://upload.wikimedia.org/wikipedia/commons/thumb/8/80/Emojione_1F600.svg/64px-Emojione_1F600.svg.png"),
SAD("sad", "https://upload.wikimedia.org/wikipedia/commons/thumb/4/42/Emojione_1F62D.svg/64px-Emojione_1F62D.svg.png")
;
private final Image emoji;
private final String value;
Feeling(String value, String url) {
// load image in background
emoji = new Image(url, true);
this.value = value;
}
public Image getEmoji() {
return emoji;
}
public String getValue() {
return value;
}
}
Code in der Anwendungsklasse
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.collections.FXCollections;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.image.ImageView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;
public class EmotionTable extends Application {
public static class Item {
private final ObjectProperty<Feeling> feeling;
public Item(Feeling feeling) {
this.feeling = new SimpleObjectProperty<>(feeling);
}
public final Feeling getFeeling() {
return this.feeling.get();
}
public final void setFeeling(Feeling value) {
this.feeling.set(value);
}
public final ObjectProperty<Feeling> feelingProperty() {
return this.feeling;
}
}
@Override
public void start(Stage primaryStage) {
TableView<Item> table = new TableView<>(FXCollections.observableArrayList(
new Item(Feeling.HAPPY),
new Item(Feeling.HAPPY),
new Item(Feeling.HAPPY),
new Item(Feeling.SAD),
null,
new Item(Feeling.HAPPY),
new Item(Feeling.HAPPY),
new Item(Feeling.SAD)
));
EventHandler<ActionEvent> eventHandler = new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
// change table items depending on userdata of source
Node source = (Node) event.getSource();
Feeling targetFeeling = (Feeling) source.getUserData();
for (Item item : table.getItems()) {
if (item != null) {
item.setFeeling(targetFeeling);
}
}
}
};
TableColumn<Item, Feeling> feelingColumn = new TableColumn<>("Feeling");
feelingColumn.setCellValueFactory(new PropertyValueFactory<>("feeling"));
// use custom tablecell to display emoji image
feelingColumn.setCellFactory(new Callback<TableColumn<Item, Feeling>, TableCell<Item, Feeling>>() {
@Override
public TableCell<Item, Feeling> call(TableColumn<Item, Feeling> param) {
return new EmojiCell<>();
}
});
table.getColumns().add(feelingColumn);
Button sunshine = new Button("sunshine");
Button rain = new Button("rain");
sunshine.setOnAction(eventHandler);
rain.setOnAction(eventHandler);
sunshine.setUserData(Feeling.HAPPY);
rain.setUserData(Feeling.SAD);
Scene scene = new Scene(new VBox(10, table, new HBox(10, sunshine, rain)));
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}
Zellklasse
import javafx.scene.control.TableCell;
import javafx.scene.image.ImageView;
public class EmojiCell<T> extends TableCell<T, Feeling> {
private final ImageView image;
public EmojiCell() {
// add ImageView as graphic to display it in addition
// to the text in the cell
image = new ImageView();
image.setFitWidth(64);
image.setFitHeight(64);
image.setPreserveRatio(true);
setGraphic(image);
setMinHeight(70);
}
@Override
protected void updateItem(Feeling item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
// set back to look of empty cell
setText(null);
image.setImage(null);
} else {
// set image and text for non-empty cell
image.setImage(item.getEmoji());
setText(item.getValue());
}
}
}
Schaltfläche zur Tabellenansicht hinzufügen
Sie können Tableview eine Schaltfläche oder eine andere Javafx-Komponente hinzufügen, indem setCellFactory(Callback value)
Methode setCellFactory(Callback value)
Spalte verwenden.
Beispielanwendung
In dieser Anwendung fügen wir eine Schaltfläche zu TableView hinzu. Wenn Sie auf diese Spaltenschaltfläche klicken, werden Daten in derselben Zeile wie die Schaltflächen ausgewählt und ihre Informationen gedruckt.
In der addButtonToTable()
-Methode ist der cellFactory
Callback dafür verantwortlich, der zugehörigen Spalte eine Schaltfläche hinzuzufügen. Wir definieren die aufrufbare cellFactory und implementieren ihre override-Aufrufmethode call(...)
, um TableCell
mit der Schaltfläche und dann dieser cellFactory
auf die zugehörige Spaltengruppe setCellFactory(..)
. In unserem Beispiel ist dies colBtn.setCellFactory(cellFactory)
. SSCCE ist unten:
import javafx.application.Application;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Stage;
import javafx.util.Callback;
public class TableViewSample extends Application {
private final TableView<Data> table = new TableView<>();
private final ObservableList<Data> tvObservableList = FXCollections.observableArrayList();
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
stage.setTitle("Tableview with button column");
stage.setWidth(600);
stage.setHeight(600);
setTableappearance();
fillTableObservableListWithSampleData();
table.setItems(tvObservableList);
TableColumn<Data, Integer> colId = new TableColumn<>("ID");
colId.setCellValueFactory(new PropertyValueFactory<>("id"));
TableColumn<Data, String> colName = new TableColumn<>("Name");
colName.setCellValueFactory(new PropertyValueFactory<>("name"));
table.getColumns().addAll(colId, colName);
addButtonToTable();
Scene scene = new Scene(new Group(table));
stage.setScene(scene);
stage.show();
}
private void setTableappearance() {
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.setPrefWidth(600);
table.setPrefHeight(600);
}
private void fillTableObservableListWithSampleData() {
tvObservableList.addAll(new Data(1, "app1"),
new Data(2, "app2"),
new Data(3, "app3"),
new Data(4, "app4"),
new Data(5, "app5"));
}
private void addButtonToTable() {
TableColumn<Data, Void> colBtn = new TableColumn("Button Column");
Callback<TableColumn<Data, Void>, TableCell<Data, Void>> cellFactory = new Callback<TableColumn<Data, Void>, TableCell<Data, Void>>() {
@Override
public TableCell<Data, Void> call(final TableColumn<Data, Void> param) {
final TableCell<Data, Void> cell = new TableCell<Data, Void>() {
private final Button btn = new Button("Action");
{
btn.setOnAction((ActionEvent event) -> {
Data data = getTableView().getItems().get(getIndex());
System.out.println("selectedData: " + data);
});
}
@Override
public void updateItem(Void item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
setGraphic(btn);
}
}
};
return cell;
}
};
colBtn.setCellFactory(cellFactory);
table.getColumns().add(colBtn);
}
public class Data {
private int id;
private String name;
private Data(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int ID) {
this.id = ID;
}
public String getName() {
return name;
}
public void setName(String nme) {
this.name = nme;
}
@Override
public String toString() {
return "id: " + id + " - " + "name: " + name;
}
}
}