Javafx TableView refresh

hallo,

ich hab mitbekommen und gesehen, dass es bei Javafx einen Methode .refresh() gibt, welches die Tabelle aktualisiert, jedoch existiert bei mir diese Methode nicht, ich bekomme immer nur eine Fehlermeldung.
Muss man da etwas noch beachten, oder wieso geht es bei mir nicht?

nach API sieht es nicht danach aus, vielleicht so?..
java - JavaFX 2.1 TableView refresh items - Stack Overflow
bzw. tippe deine drei Wörter vom Thementitel in Suchmaschine ein für entsprechende Ergebnisse

wenn das hier die richtige API ist, dann gibt es generell keine refresh()-Methode irgendwo
https://docs.oracle.com/javase/8/javafx/api/index-all.html#I:R

was ich für bemerkenswert halte, allerdings in der großen Java-API allgemein auch nur 6x, in Nebenklassen wie Policy…

komisch, ich hab von einem Freund ein teil code bekommen, wo diese refresh() enthalten ist, und auch da zeigt es bei mir rot unterstrichen, aber wenn ich mit STRG und Mausklick rein gehe bekomme ich in der tat eine Methode:

/**
     * Call this function to force the TableView to re-evaluate itself. This is
     * useful when the underlying data model is provided by a TableModel, and
     * you know that the data model has changed. This will force the TableView
     * to go back to the dataProvider and get the row count, as well as update
     * the view to ensure all sorting is still correct based on any changes to
     * the data model.
     */
    private void refresh() {
        getProperties().put(TableViewSkinBase.REFRESH, Boolean.TRUE);
    }```

Was sagt denn die Fehlermeldung genau?! Je nach IDE sollte die ja irgendwo erscheinen, z.B. in einem Fehlerausgabe-Fenster, oder in einem Tooltip, wenn man mit der Maus über dem rot unterstrichenen stehenbleibt…

Die Methode ist private, d.h. sie kann nur intern aufgerufen werden.

„Call this function to force the TableView to re-evaluate itself.“ in Suchmaschinen findet Hinweise

in
openjfx/2.1/master/rt: 682bde65e6d3 javafx-ui-controls/src/javafx/scene/control/TableView.java
dabei, was nach alter Version 2.1 aussieht

in
openjfx/8u-dev/rt: 639794806c6c
‚RT-22599: Ability to force a ListView or TableView refresh‘
rot angestrichen, vielleicht entfernt oder erst Vorschlag…, überhaupt openjfx, ist das was besonders? Fragen über Fragen…


[8u60] API Review for RT-22599: Ability to force a ListView or TableView refresh

im Zweifel die enthaltene Methode aufrufen bzw. eigene Hilfsmethode schreiben

edit: private, ach ja, das sowieso :wink: wozu auch immer dann gedacht

Hä, da war ich wohl blind :rolleyes:

Bin mit JavaFX auch nicht so vertraut, aber bei dem wenigen, was ich bisher gesehen habe, war intern alles so massivst verdrahtet, dass ich mich gerade frage, wo und wann so ein manuelles update überhaupt erforderlich sein sollte…

Welche Version ist installiert?

Ab Java 8u60 ist die Methode public, kann also extern aufgerufen werden.

Im Zweifel also mal updaten!

java 8-Update 66 ist installiert, ist aber ist immer noch private

Eigentlich braucht man refresh() nicht.

Das Model einer Tableview ist eine ObservableList. Elemente hinzufügen und entfernen sorgt automatisch für ein Update der View.

Änderungen an einem Element sind ein Problem.

Daher kann man für die Elemente eine neue Klasse erstellen und dort mit Properties arbeiten.

Hier sieht man ein Beispiel mit einer Personenklasse und Properties, sowie eine Erklärung wie man damit Spalten erstellt.

JavaFX 8 Tutorial - Part 2: Model and TableView | code.makery.ch

Propagiert man Änderungen über die Props, dann erfolgt der refresh automatisch und auch nur darauf, was auch refresht werden muß.

Das refresh ist mMn. nur eine Krücke.

Ansonsten kann man sich noch einen Wrapper bauen, der das ganze Element wrappt und dafür Properties bereitstellt. Ähnlich dem Birthdate ObjectProperty. Ist allerdings etwas tricky aber machbar.

Bei der zuerst verlinkten Stackoverflow-Antwort stand, dass nicht alle Funktionen wie erwartet einen Refresh auslösen (deswegen hatte ich gefragt, um welche Änderungen es geht).

Aber vielleicht ist das bei der neuesten Version auch gefixt?!

Bzgl. der Version: Sicher, dass sich da nicht noch irgendwo eine alte JavaFX-Version ins Eclipse reinschleicht?

@Marco13 die Antwort von SO, von Uluk Biy ist nicht optimal, aber ich nehme den Code mal als Ausgangsbasis.

Angenommen ich möchte per Button den Namen jedes Elements auf “foo” setzen.
Iterieren über die Liste und setter aufrufen.

Ergebnis, es passiert nix.

Zusätzlicher Aufruf auf refresh und Änderungen sind sichtbar.

            @Override
            public void handle(ActionEvent arg0) {
                prods.stream().forEach(i -> i.setName("foo"));
             //   productTable.refresh();
            }
        });```

Aber keine gute Lösung!

Mein Ansatz

Model um StringProperties erweitern

```public static class Product {

        private final StringProperty name = new SimpleStringProperty();
        private final StringProperty code = new SimpleStringProperty();

        public Product(String name, String code) {
            this.name.set(name);
            this.code.set(code);
        }

        public String getCode() {
            return code.get();
        }

        public void setCode(String code) {
            this.code.set(code);
        }

        public String getName() {
            return name.get();
        }

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

        public StringProperty getNameProp() {
            return name;
        }

        public StringProperty getCodeProp() {
            return code;
        }
        
        
    }```

TableColumn auf Properties verweisen

```TableColumn<Product, String> nameCol = new TableColumn<>("Name");
        nameCol.setMinWidth(100);
        nameCol.setCellValueFactory(cell -> cell.getValue().getNameProp());```

Aufruf von refresh nicht mehr nötig.

KSKB

[SPOILER]
```package tableviewer;

import java.util.ArrayList;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Tableviewer extends Application {

    public static class Product {

        private final StringProperty name = new SimpleStringProperty();
        private final StringProperty code = new SimpleStringProperty();

        public Product(String name, String code) {
            this.name.set(name);
            this.code.set(code);
        }

        public String getCode() {
            return code.get();
        }

        public void setCode(String code) {
            this.code.set(code);
        }

        public String getName() {
            return name.get();
        }

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

        public StringProperty getNameProp() {
            return name;
        }

        public StringProperty getCodeProp() {
            return code;
        }
        
        
    }

    private ObservableList<Product> prods = FXCollections.observableArrayList();

    @Override
    public void start(Stage stage) {
        final TableView<Product> productTable = new TableView<Product>(prods);
        Button refreshBtn = new Button("Refresh table");
        refreshBtn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent arg0) {
                // You can get the new data from DB
                List<Product> newProducts = new ArrayList<Product>();
                newProducts.add(new Product("new product A", "1201"));
                newProducts.add(new Product("new product B", "1202"));
                newProducts.add(new Product("new product C", "1203"));
                newProducts.add(new Product("new product D", "1244"));

                prods.clear();
                prods.addAll(newProducts);
            }
        });

        Button changeBtn = new Button("Change table");
        changeBtn.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent arg0) {
                prods.stream().forEach(i -> i.setName("foo"));
             //   productTable.refresh();
            }
        });
        
        TableColumn<Product, String> nameCol = new TableColumn<>("Name");
        nameCol.setMinWidth(100);
        nameCol.setCellValueFactory(cell -> cell.getValue().getNameProp());

        TableColumn<Product, String> codeCol = new TableColumn<>("Code");
        codeCol.setCellValueFactory(cell -> cell.getValue().getCodeProp());
        
        productTable.getColumns().addAll(nameCol, codeCol);
        productTable.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);

        // You can get the data from DB
        List<Product> products = new ArrayList<Product>();
        products.add(new Product("product A", "0001"));
        products.add(new Product("product B", "0002"));
        products.add(new Product("product C", "0003"));

        prods.addAll(products);
        

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.getChildren().addAll(productTable, refreshBtn, changeBtn);

        Scene scene = new Scene(new Group());
        ((Group) scene.getRoot()).getChildren().addAll(vbox);
        stage.setScene(scene);
        stage.setWidth(300);
        stage.setHeight(500);
        stage.show();
    }

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

Hmja, das zielt wohl auch darauf ab: Strukturelle Änderungen (Hinzufügen oder Entfernen von Elementen) vs. Inhaltsänderungen (also Änderung einer Property in einem angezeigten Objekt). Aber solange keine weiteren Nachfragen o.ä. kommen, ist die Frage wohl beantwortet.

Ich hab die Lösung gefunden, auf mein Betriebssystem war zwar java 8u66 installiert, aber nicht auf mein eclipse, da war es noch auf java 8u25.
Ich danke an euch, eure Lösungen waren auch hilfreich!