FX Table - Generische Daten

Hallo Liebe Community!

Leider muss ich euch wieder mal um euren Rat bitten.

Derzeit habe ich ein Problem das ich für meine Diplomarbeit eine FX Table erstellen muss und für diese eine generische Klasse brauche um die Table zu befüllen.

Leider weiß ich erst zur Laufzeit wie diese Table aussehen sollen bzw wie das zu erstellende Objekt aussehen soll.

Habt ihr eine Idee wie ich das am Besten Lösen kann?

Hier einige Beispiele:

Ich müsste zur Laufzeit ein Objekt generieren mit z.B

String geburtsort = file.getGeb();```

(ich müsste dann allerdings auch wissen wie die Properties des Objektes heißen, da ich diese später für die table benötige)
```GenericClass tableObject = new GenericClass(vorname, geburtsort);```

oder 


```String vorspeise = file.getVorspeise();
String hauptspeise = file.getHauptspeise();
String nachspeise = file.getNachspeise();
double preis = file.getPreis();
date termin = file.getTermin();```

(ich müsste dann allerdings auch wissen wie die Properties des Objektes heißen, da ich diese später für die table benötige)
```GenericClass tableObject = new GenericClass(vorspeise , hauptspeise,nachspeise, preis, termin);```


Weil danach müsste ich dann meiner table die jeweiligen Variabeln der Objekte zuweisen. 
Der konkrekte Ablauf würde dann im Programm so aussehen:

private TableView table = new TableView();
table.setEditable(true);

TableColumn firstNameCol = new TableColumn(“First Name”);
TableColumn lastNameCol = new TableColumn(“Last Name”);
TableColumn emailCol = new TableColumn(“Email”);

table.getColumns().addAll(firstNameCol, lastNameCol, emailCol);

final ObservableList data = FXCollections.observableArrayList(
new GenericClass(“Jacob”, “Smith”, "jacob.smith@example.com"),
new GenericClass(“Isabella”, “Johnson”, "isabella.johnson@example.com"),
new GenericClass(“Ethan”, “Williams”, "ethan.williams@example.com"),
new GenericClass(“Emma”, “Jones”, "emma.jones@example.com"),
new GenericClass(“Michael”, “Brown”, "michael.brown@example.com")
);

(Hier müsste ich dann wissen wie die Properties im Objekt heißen)

```firstNameCol.setCellValueFactory(
    new PropertyValueFactory<Person,String>("Property1")
);
lastNameCol.setCellValueFactory(
    new PropertyValueFactory<Person,String>("Property2")
);
emailCol.setCellValueFactory(
    new PropertyValueFactory<Person,String>("Property3")
);```


Ich hoffe ich habe mein Problem halbwegs verständlich geschildert.

Vielen Dank für eure Hilfe!

Liebe Grüße

Johannes

Sieh mir hier danach aus, als wärest Du mit einer Map<String,String> am besten dran. Die Keys der Map sind Deine Property-Names, die Values die Values. Für jedes neue “Objekt” eine neue Map.

Das mit der Tabellendarstellung von Klassen mit unterschiedlichen Properties macht nicht wirklich Sinn. Was wären denn da die Spaltenüberschriften?

Hey, danke für die rasche Antwort!

Also die Spaltenüberschrift bekomme ich dann auch zur Laufzeit.

Wenn ich es mit einer Hashmap machen würde, kann ich es aber nicht in der Table darstellen, oder?
Denn die FX Table benötigt ja Objekte, oder nicht?

LG

Ich denke auch, daß du mit einer Map gut bedient bist.

Wenn erst zur Laufzeit bekannt ist was gebraucht wird, dann wird es schon sehr kompliziert.

Da kommst du dann irgendwann zu Reflections und InvokationProxys mit denen du dann Klassen generierst. Evtl. benötigst du auch noch Wrapper für die Datentypen etc.pp. Aber das ist dann mMn. schon die höhere Schule der Programmierkunst.

Für diese Geschichten sind dann dynamisch Typisierte Sprachen besser ausgelegt. Ruby zum Beispiel. Mit JRuby wird intern höchstwahrscheinlich schon das selbe wie oben beschrieben gemacht.

Also wäre euer Rat das ich es mit einer Hashmap machen sollte?

Und wie würdet ihr die Daten dann von der Hashmap in die Table laden?

ui, JavaFX Table geht tatsächlich direkt auf Variablennamen,
das hätte ich nicht gedacht für so ein modernes Framework, welch rückständig unflexibles Verhalten, wie man hier sieht,
da ist die simple JTable mit getValueAt(x,y) geeigneter, selbst vor der Zeit/ ohne Generics

aber kein Weg lang genug, ihn nicht nicht umzuleiten, dann musst du den Welt-Standard ( :wink: ) eben nachbauen

    new PropertyValueFactory<Person,String>("Property1")
);
lastNameCol.setCellValueFactory(
    new PropertyValueFactory<Person,String>("Property2")
);
emailCol.setCellValueFactory(
    new PropertyValueFactory<Person,String>("Property3")
);```

hast du selber schon geschrieben, das ist eine Möglichkeit, auf die standardisiert benannten Felder einer allgemeinen Klasse verweisen,
die Klasse kann ruhig gleich 20 Felder haben, wenn man nur drei aktuell nutzen will, dann nur diese drei befüllen,
nur drei Colums + 'PropertyValueFactory's setzen

aus der Map Objekte zu befüllen sollte machbar sein, allein Reihenfolge nicht gegeben, außer bei LinkedHashMap,
wobei Keys dann vielleicht gar nicht mehr benötigt, eine simple Liste/ Array könnte schon besser sein, dann mit Reihenfolge

aber es bietet sich sowieso neben der Liste der Objekte ein übergeordnetes Objekt/ Klasse an mit Beschreibung (Name/ Typ der enthaltenen Objekte, hier etwa 'Person'), 
allgemeine Liste der Felder mit Namen/ Datentyp (Zahl, Text, Datum), jeweils sonstige Informationen wie Pflichtfeld, Darstellungshinweise, Min/Max-Länge usw.

Leider darf ich auch keine normale JTable verwenden, da die Diplomarbeit über Java FX handelt und ich nur Java FX Elemente für die Diplomarbeit verwenden darf.

hast du selber schon geschrieben, das ist eine Möglichkeit, auf die standardisiert benannten Felder einer allgemeinen Klasse verweisen,
die Klasse kann ruhig gleich 20 Felder haben, wenn man nur drei aktuell nutzen will, dann nur diese drei befüllen,
nur drei Colums + 'PropertyValueFactory’s setzen

Mein Betreuer für die Diplomarbeit hat leider gesagt, dass das keine zulässige Variante ist. Er meinte einfach eine Klasse mit 30 Felder zu machen sei einfach nicht professionell, da es theoretisch auch möglich ist das 31 Felder benötigt werden könnten…

aus der Map Objekte zu befüllen sollte machbar sein, allein Reihenfolge nicht gegeben, außer bei LinkedHashMap,
wobei Keys dann vielleicht gar nicht mehr benötigt, eine simple Liste/ Array könnte schon besser sein, dann mit Reihenfolge

Also eine HashMap klingt gut, Problem ist nur wie ich dann daraus die jeweiligen Objekte erstelle.

aber es bietet sich sowieso neben der Liste der Objekte ein übergeordnetes Objekt/ Klasse an mit Beschreibung (Name/ Typ der enthaltenen Objekte, hier etwa ‚Person‘),
allgemeine Liste der Felder mit Namen/ Datentyp (Zahl, Text, Datum), jeweils sonstige Informationen wie Pflichtfeld, Darstellungshinweise, Min/Max-Länge usw.

Leider kann ich hier nicht genau folgen was du meinst.
Dann bräuchte ich ja wieder statische Klassen. Ziel sollte es sein mit einer Klasse (die dynamische ist) alle Objekte abbilden (erzeugen) zu können.

Also ich finde die Idee mit der HashMap sehr gut, damit kann ich dann mit verschiedenen keys z.B vorname, nachname, gebDatum die einzelnen Felder festlegen und dort die Daten speichern.

Ich müsste jetzt nur noch anhand der HashMap ein Objekt erstellen können. (dieses sollte natürlich dann auch die jeweiligen Datentypn beinhalten → String vorname, String nachname, Date gebDatum

Danke für deine Hilfe :smiley:

LG

im alten Forum gab es einen schönen FAQ-Eintrag ‚Fragen zu Variablennamen‘
http://www.java-forum.org/top-fragen/62032-fragen-variablennamen.html

Klassen anlegen mit bestimmten Feldern/ Methodennamen ist ganz ganz hinten in der Menge der Möglichkeiten,
vielleicht nur praktikabel mit Quellcode schreiben und kompilieren lassen…, aber lieber gar nicht drüber nachdenken,


ich habe zum Glück auch JavaFX unterschätzt,
setCellValueFactory( new PropertyValueFactory
schreit ja fast nach Existenz von Alternativen,

nicht allzu leicht zu finden, aber mit MapValueFactory ist auch genau eine Variante für Maps vorhanden, super,
siehe java - Inserting data in a TableView Javafx - Stack Overflow
Posting „After wasting my day i finally able to find the solution in very easy way“ gegen Ende


eine übergeordnete Klasse bietet sich meiner Meinung nach immer noch an, a la

class PackOfData {
   String type; // "Person";
   List<String> columns; // "First Name", "Last Name","Email", Daten + Reihenfolge, evtl. ausbauen zu Typ der Spalten usw.
   List<Map<String, Object>> rows; // je Eintrag eine Map
   // + was immer sonst noch helfen kann
}

besser als nur eine Liste von Maps


edit:

man könnte theoretisch auch begrenzen, nicht bei 30, dann eben aber bei 300

es gibt ein nicht gerade unbekanntes Programm namens Excel, das bei mehr als 256 Spalten streikt…
zwar von keiner guten Firma, aber sollte als Halb-Professionalität reichen

Ich danke dir für den super Tipp!

Werde ich gleich mal ausprobieren und dann bescheid geben, ob es mit der von dir geschilderten Variante funktioniert :slight_smile:

man könnte theoretisch auch begrenzen, nicht bei 30, dann eben aber bei 300

es gibt ein nicht gerade unbekanntes Programm namens Excel, das bei mehr als 256 Spalten streikt…
zwar von keiner guten Firma, aber sollte als Halb-Professionalität reichen

Ja ich hätte eig auch an so etwas Gedacht, aber dem Lehrer ist das leider nicht so recht ;D

Also ich habe jetzt eine Klasse PackOfData gemacht

public class PackOfData {
    private String type; //z.B Person, Maschine etc.
    List<String> columns; // z.B "Vorname", "Nachname", "Email", Daten + Reihenfolge, evtl. ausbauen zu Typ der Spalten usw.
    //List<Map<String, Object>> rows; // je Eintrag/Zeile eine Map
    ObservableList<Map<String, Object>> rows = FXCollections.observableArrayList();

    public PackOfData(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public List<String> getColumns() {
        return columns;
    }

    public ObservableList<Map<String, Object>> getRows() {
        return rows;
    }

    

    public void setType(String type) {
        this.type = type;
    }

    public void setColumns(List<String> columns) {
        this.columns = columns;
    }

    public void setRows(ObservableList<Map<String, Object>> rows) {
        this.rows = rows;
    }
}

und dann die Daten der Table / Maps hinzugefügt

    private VBox GetTable(String tableName, List preferedDimension, String statement, List nonDisplayRow, ButtonInformation bInfo, int textSize) {
        TableView table = new TableView<>();
        Label label = new Label(tableName);
        label.setFont(new Font(textSize *2));
        table.setMinHeight(tableHeight);
        table.setMinWidth(tableWidth);
        table.setMaxHeight(tableHeight);
        table.setMaxWidth(tableWidth);
        ObservableList<ExampleTable> data;
        
        
        String type = "Essen";
        List<String> listOfColumns = new LinkedList<String>();
            listOfColumns.add("Vorspeise");
            listOfColumns.add("Hauptspeise");
            listOfColumns.add("Nachspeise");
        ObservableList<Map<String, Object>> rows;
//        List<Map<String, Object>> rows = new LinkedList<Map<String, Object>>();
        rows = GetTableData();
       
        
        PackOfData tableData = new PackOfData(type);
        tableData.setColumns(listOfColumns);
        tableData.setRows(rows);
        
        for (int i = 0; i < tableData.getColumns().size(); i++) {
            TableColumn<Map, String> col = new TableColumn<Map, String>(tableData.getColumns().get(i));
            col.setCellValueFactory(new MapValueFactory<String>(tableData.getColumns().get(i)));
            col.setMinWidth(333);
            table.getColumns().add(col);
        }

        table.setItems(rows);
        
        table.setStyle("-fx-font-size: "+textSize+"px;");
        VBox vbox = new VBox();
        vbox.setSpacing(5);
        vbox.setPadding(new Insets(10, 0, 0, 10));
        vbox.getChildren().addAll(label, table);   
        vbox.setAlignment(Pos.CENTER);
        return vbox;
    } 

und es funktioniert :slight_smile:

Ich danke dir vielmals!!!