JavaFX Tabelle zeilenweise mit Werten füllen und an Container anpassen

Bitte aktiviere JavaScript!
Hallo allerseits

Ich beschäftige mich seit gestern mit JavaFX. Ich habe eine Tabelle erstellt und will diese mit Werten füllen. So, wie mir die Daten vorliegen, wäre mir zeilenweises Schreiben am liebsten.
Ein weiteres Problem: Jede zweite Zeile soll als eine Art Überschrift dienen. Daher will ich einen Teil oder alle Zellen jede zweiter Zeile verbinden. So etwa:
Code:
| Zelle1 | Zelle2 | . . . . .Zelle3 - Zelle 6. . . . |
| Zelle1 | Zelle2 | Zelle3 | Zelle4 | Zelle5 | Zelle6|
| Zelle1 | Zelle2 | . . . . .Zelle3 - Zelle 6. . . . |
| Zelle1 | Zelle2 | Zelle3 | Zelle4 | Zelle5 | Zelle6|
Zusätzlich werden sich die Zellwerte selber nicht allzuhäufig ändern, wahrscheinlich sogar gar nicht, dafür werden aber oft neue Zeilen oder gleich ganze Spalten hinzukommen.

Und nun: Wie mache ich das am Besten?

Später soll der Benutzer alle Zellen/Zellverbände anklicken können und ich möchte dann wissen, welche er angeklickt hat. Aber das ist der nächste Schritt, wenn die Tabelle angezeigt wird wie ich das haben will bin ich schon froh. :)

Und noch etwas zur Formatierung der Tabelle: Die Tabelle hab ich in ein Scrollpane gepackt, denn die kann mal größer als das Fenster werden. (Die ScrollPane liegt in einem Tab, der in einem SplitPane liegt, dieser in einem BorderPane...)
Code:
//Fill library stamp tab
ScrollPane scrollPane= new ScrollPane();
tab.setContent(scrollPane);
centerviewTable = new TableView();
centerviewTable.setEditable(true);

centerviewTable.setColumnResizePolicy(TableView.UNCONSTRAINED_RESIZE_POLICY);
scrollPane.setContent(centerviewTable);
Die Tabelle wird aber nur so groß angezeigt, wie sie ist. Ich hätte nun gerne, daß die mindestens bis zur Größe des Fensters aufgeblasen wird. Hat da jemand eine Idee?
Ich hab es u.a. mit einem BorderLayout probiert, aber das funktionierte alles nicht.
 
A

Anzeige


Vielleicht hilft dir dieser Kurs hier weiter: (hier klicken)
Kleiner Nachtrag:
Ich habe mal auf gut Glück etwas an diesem Beispiel herumprobiert:
http://java-buddy.blogspot.com/2013/03/javafx-editable-tableview-with-dynamic.html

Ich hab die Beispiele mit dem Observables und CallBack nicht verstanden weil ich nicht erkennen konnte, wie die Tabelle (bzw. die CellFactory) erkennen kann welche Methode sie aufrufen muß.
Da die Methode getId() nirgendwo erkennbar im Code aufgerufen wird hab ich sie einfach mal in getBlah() umbenannt, und schon bleibt die Spalte "ID" in der Tabelle leer.

Wenn ich jetzt aber die Zeile 132
Code:
col_id.setCellValueFactory(
                    new PropertyValueFactory<Record, String>("id"));
umändere in:
Code:
col_id.setCellValueFactory(
                    new PropertyValueFactory<Record, String>("blah"));
dann funktioniert es wieder-hä?

Das einzige was mir einfällt wie das funktonieren könnte wäre Reflexion. Aber das hab ich bisher immer als wildes Hackerzeugs angesehen und auch selber nur benutzt, wenn ich in Unittests private Methoden aufbrechen wollte weil ich dann doch mal im Test das innere Verhalten meiner Klasse beobachten wollte/mußte.

Aber mal ehrlich-das kann doch nicht der von den Java-Leuten gewollte Weg sein, eine dämliche Tabelle mit Leben zu füllen? Da muß es doch noch einen vernünftigen Weg geben, oder nicht? Einerseits sehe ich wirklich nicht wie ich so nacher Zellen verbinden kann, und wehe man refakturiert unvorsichtig...und wie soll ich zur Laufzeit Methoden zu meiner Klasse hinzufügen?

Oder tue ich den Javaentwicklern da gerade großes Unrecht an und mir kommt das nur völlig umständlich vor?
 
Aber das hab ich bisher immer als wildes Hackerzeugs angesehen
Dieses wilde Hackerzeug aber auch. Dazu dann noch diese geheimnisvollen Java Beans - voll crazy ;)

Aber mal ehrlich-das kann doch nicht der von den Java-Leuten gewollte Weg sein, eine dämliche Tabelle mit Leben zu füllen
Die View vom Model zu entkoppeln ist durchaus gewollt. Google mal nach MVC.

Oder tue ich den Javaentwicklern da gerade großes Unrecht an und mir kommt das nur völlig umständlich vor?
Sagen wir mal so: es ist völlig klar, dass der Aufwand mit der Flexibilität steigt.

Daher will ich einen Teil oder alle Zellen jede zweiter Zeile verbinden.
Soweit ich das sehe, funktioniert das (noch) nicht von Haus aus. Du willst eher etwas wie das hier: https://github.com/controlsfx/controlsfx, speziell https://controlsfx.bitbucket.io/org/controlsfx/control/spreadsheet/SpreadsheetView.html
 
Hallo mihe7

Erstmal ein frohes neues Jahr und viel Erfolg in selbigem.

Hm, controlsfx...jetzt weiß ich warum ich diesen Artikel auf fxexperience absolut nicht verstanden habe. Vielen Dank, daß sieht tatsächlich nach dem aus was ich will. :)

View und Model zu entkoppeln hab ich schon vor, das MVC-Muster ist mir bekannt. Auch wenn ich es jetzt zum ersten Mal anwende.
 
Das klappt ja schonmal gut mit der SpreadsheetViewklasse. Spalten und Zeilen erstellen funktoniert. :)

Allerdings hänge ich jetzt bei einer Sache, die mit der alten TableViewklase schon funktioniert hat: ich möchte einer Gruppe von Spalten einen gemeinsamen Header zuweisen.
Die Tableview hab ich einfach mit Columnobjekten gefüttert (das erste Columnobjekt hab ich vorher aus mehreren anderen Columnobjekten erstellt). Das Ergebnis sah so aus:



Und das hätte ich jetzt gern wieder. Ich sehe nur nicht, wie ich das in der Spreadsheetview machen kann. Es gibt zwar eine Spreadsheetcolumnklasse, aber die kann ich nicht instanzieren.

Hast du da noch eine Idee?
 

Anhänge

Kleiner Nachtrag:
Genau genommen hab ich nicht versucht, das über das Spreadsheetviewobjekt, sondern über das BaseGridobjet zu arbeiten. Ich hoffe es ist trotzdem klar was ich meinte.

Und nochwas: Wieso kann ich meinen Beitrag nicht editieren? (Bzw. wo geht das?)

Ach, ich sehs grad selber. Scheint zeitbegrenzt zu sein...
 
So...mittlerweile krieg ich es hin, der Spreadsheetview einen vernünftiegn Header zu verpassen und mit Werten zu füllen.

Was ich noch nicht hinbekomme: Wie kann ich da jetzt Zellen verbinden? Im HelloSpreadsheetview-Beispiel von controlsfx geht das wohl anscheinend über die Grid.spanColumn()-Methode. Ich hab da im Beispiel mal spaßeshalber den ein oder anderen Parameter geändert und da hat das gut funktioniert.
Bei mir führt die spanColumn()-Methode höchstens dazu, daß die Zellen komplett verschwinden. Gelegentlich auch die entsprechenden Spalten.

Auch die SpreadsheetCell-Klasse stellt so eine setColumnSpan()-Methode zur Verfügung, auch die createCell()-Methode hat dafür Übergabeparameter. Die würde ich am liebsten verwenden, erhalte da aber das gleiche Ergebnis.

Hier mal etwas Code, wie ich das erstelle. Sieht jemand, was da noch fehlt?
Ich füttere das Ganze aktuell immer mit den gleichen Daten, es kommt erstmal immer eine 2x6-Tabelle raus.
Code:
       LibraryPage activePage;
       Grid grid;
       Iterator<StampSet> stampsetIterator;
       ObservableList<ObservableList<SpreadsheetCell>> rows;
       StampSet stampset;
       double tablewidht;
       int rowcnt;

       activePage = model.getActiveLibrayPage();

       //Create tableheader
       grid = new GridBase(activePage.cntStampSets() * 2, activePage.cntAllProperties());
       tablewidht = 0;
       //Temporary properties
       for (String s : activePage.getTemporaryProperties()) {
           grid.getColumnHeaders().add(s);
           tablewidht += (s.length() * 8.5);
       }
       //Persistant properties
       for (String s : activePage.getPersistantProperties()) {
           grid.getColumnHeaders().add(s);
           tablewidht += (s.length() * 8.5);
       }
       //Fill table alternatig with stampset name and its stamp descriptions
       rows = FXCollections.observableArrayList();
       stampsetIterator = activePage.getStampSetIterator();
       rowcnt = 0;
       while (stampsetIterator.hasNext()) {
           stampset = stampsetIterator.next();
           rows.add(getRowWithStampSetName(activePage, stampset));
           rowcnt++;
           //rows.add(getRowWithStampDescriptions(activePage.getAllProperties(), stampset));
           rowcnt++;
       }
       grid.setRows(rows);
//       grid.spanColumn(3, 0, 3);
      
       //Do some grid formatting
       centerviewStamptable.setMinWidth(tablewidht);
       centerviewStamptable.setGrid(grid);
       for(int i = 0; i < grid.getColumnCount(); i++){
           int preferedLenght = grid.getColumnHeaders().get(i).length()*10;
           centerviewStamptable.getColumns().get(i).setPrefWidth(preferedLenght);
       }
       centerviewStamptable.setVisible(true);


    private ObservableList<SpreadsheetCell> getRowWithStampSetName(LibraryPage page, StampSet stampSet) {
       ObservableList<SpreadsheetCell> row;
       SpreadsheetCell cell;
       String stampname = stampSet.getName();
       int temporaries = page.getTemporaryProperties().size(); //Todo: Durch Methode cntAllTemporaries ersetzen
       int persistants = page.getPersistantProperties().size(); //Todo: Durch Methode cntAllPersistants ersetzen
       int cellsmax = page.cntAllProperties();

       row = FXCollections.observableArrayList();
       for (int i = 0; i < temporaries; i++) {
           cell = SpreadsheetCellType.STRING.createCell(i, 0, 0, 0, "");
           row.add(cell);
       }
       cell = SpreadsheetCellType.STRING.createCell(temporaries, 0, 1, 3, stampname);
//       cell = SpreadsheetCellType.STRING.createCell(temporaries, 0, 1, 1, stampname);
//       cell.setColumnSpan(3);
//       for(int i = temporaries ; i < cellsmax; i++){
           row.add(cell);
//       }
       return row;
   }
 
Schade, hat niemand eine Idee?

Ich hab hier noch zwei Screenshots von dem, was mein Programm bisher liefert.
Im ersten Bild hab ich den columnspan-Aufruf rausgenommen.
ohne columnspan.PNG

Und im zweiten Bild hat ich die columnspan-Aufruf auf die erste Zeile angewandt. Jetzt ist da nichts mehr, es wird auch kein anderer Hintergrund gezeigt wenn man mt der Maus darübergeht.
mit columnspan 1. Zeile.PNG
 
JAAAAHAHAHA, endlich funktoniert es.

Eigentlich wollte ich das Minimalprogramm posten und fragen wo es klemmt, während des Schreibens ging es dann aber doch irgendwann. :)

Für Interessierte poste ich das Programm trotzdem:
Code:
package commontests;

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;
import org.controlsfx.control.spreadsheet.Grid;
import org.controlsfx.control.spreadsheet.GridBase;
import org.controlsfx.control.spreadsheet.SpreadsheetCell;
import org.controlsfx.control.spreadsheet.SpreadsheetCellType;
import org.controlsfx.control.spreadsheet.SpreadsheetView;

/**
 *
 * @author White_Fox
 */
public class SpreadsheetviewTest extends Application{
   
   public static void main(String[] args) {
       launch(args);
   }

   @Override
   public void start(Stage primaryStage) throws Exception {
       BorderPane rootPane = new BorderPane();
       Scene mainscene = new Scene(rootPane, 1000, 600);
               
       Grid grid;
       SpreadsheetView view;
       ObservableList<SpreadsheetCell> row;
       ObservableList<ObservableList<SpreadsheetCell>> rows;
       SpreadsheetCell cell;
       String s;
       
       view = new SpreadsheetView();
       grid = new GridBase(4, 4);
       rootPane.setCenter(view);
       primaryStage.setScene(mainscene);
       primaryStage.show();
       
       rows = FXCollections.observableArrayList();
       
       for (int i = 0; i < 4; i++) {
           row = FXCollections.observableArrayList();
           for (int j = 0; j < 4; j++) {
               s = "x";
               if((i == 1 || i == 2) && (j == 1 || j == 2)){
                   s = "s";
               }
               cell = SpreadsheetCellType.STRING.createCell(i, j, 1, 1, s);
               row.add(cell);
           }
           rows.add(row);
       }
       grid.setRows(rows);
       grid.spanColumn(2, 1, 1);
       grid.spanColumn(2, 2, 1);
       view.setGrid(grid);
   }
}
Jetzt muß ich nur noch zusehen was in meinem eigentlichen Programm noch klemmt. Kann ja nicht so viel sein...
 
So...ich nochmal.

Die Spreadsheetview funktioniert ganz gut und zeigt alles so an wie ich will, hat aber noch eine Häßlichkeit: Sie läßt sich schlecht an die Fenstergröße anpassen und so wie ich das bisher sehe, ist das auch nicht so einfach machbar.
Im Prinzip will ich genau das gleiche wie der hier (nur mit Spreadsheetview anstatt der TableView):
https://stackoverflow.com/questions/32510309/resizing-tableview-to-fit-scrollpane

Jetzt überlege ich mir, das mit TableView2 zu machen und stoße wieder auf das Problem der unsäglichen Datenanzeige. Ich weiß zur Kompilierzeit nicht, wie die Daten heißen die ich anzeigen lassen will und kann dementsprechend keine Methoden bereitstellen.

Frage:
Hat jemand eine Idee, wie die Spreadsheetview an die Größe eines TabPanes angepasst werden kann (und mitgeht, wenn die Fenstergröße geändert wird)? Wäre mir am liebsten, da weniger Umbau.

Alternativ:
Kennt jemand einen Weg, die TableView2 auf anderen Wegen mit Daten zu füllen? Eine Liste übergeben oder so? So wie ich das gerade sehe gibt das Codebeispiel von den Machern leider nichts anderes her. :(

Wenn es nicht anders geht: Ich nehm auch alternative Vorschläge...
 
Jippieh, jetzt hab ich es endgültig gelöst. Für die die dasselbe Problem haben:
Zunächst hab ich die Spreadsheetview in eine TabPane geworfen. Das hatte die merkwürdige Größe der Spreadsheetview zur Folge.

Jetzt hab ich die Spreadsheetview in eine StackPane gelegt, und die StackPane in die TabPane gelegt und nun ist die Spreadsheetview genauso groß wie die TabPane und geht mit wenn die Größe der TabPane geändert wird.
 
Nur rein zu Info-Zwecken: War kürzlich auf den JavaFX Days in Zürich. Auch, weil ich den Veranstalter und einige der Typen teils persönlich kenne (aber nur vom Quatschen und Twitter-"Friend" :D, jetzt nicht super-Dicke, aber man kennt sich halt), die in der JavaFX-Scene recht bekannt sind - z.B. den jetzigen JavaFX-Co-Lead, Johan Vos.

Kernaussage zum Thema TableView, dem sich die meisten angeschlossen haben: TableView sucks! ;)
Ich denke @mihe7 hat schon ein paar gute Tipps ausgegraben. Auch wenn ich mit JavaFX recht gut zurecht komme, hätte ich für dein Thema, @White_Fox, auch erst einmal recherchieren müssen...
 
PS: @White_Fox Glückwunsch, dass du dein Problem in den Griff bekommen hast!
Neugierige Frage meinerseits: Verwendest du bereits OpenJavaFX 11 oder noch JavaFX 8?
 
Hallo dzim
Ich arbeite gerade mit Java 8.

Ich denke zwar nicht daß Oracle mir wegen meinem Programm eine Rechnung schicken wird (es bleibt eine Einzel-PC-Anwendung, möglicherweise werde ich sie auch bei Sourceforge reinstellen wenn ich mit dem Ergebnis ausreichend zufrieden bin), dennoch würde ich lizenztechnisch gern sauber bleiben. Allein schon weil eine gewerbliche Nutzung nicht auszuschließen ist. Genaugenommen will ich mir damit meine tägliche Arbeit erleichtern.
Soweit ich weiß betrifft Oracles Wunsch, die Java-Orange auszupressen, nur Servergedöns. Sofern "auspressen" überhaupt so gesagt werden kann, ich kann das nicht einschätzen. Ich hab nur den ein oder anderen Heise-Artikel darüber gelesen.

Wie auch immer-ich hab einfach noch keine Zeit (und Lust) gehabt den ganzen Oracle-Schriebs zu lesen. Und ehrlich gesagt auch die Englisch-Kenntnisse. Datenblätter und Forenunterhaltungen sind kein Problem, aber um Verträge juristisch einigermaßen sicher lesen zu können fehlt es mir einfach. Das ist im Deutschen schon schwer genug.

Wie gestaltet sich eigentich der Umstieg vom Oracle-JDK zu OpenJDK? Muß da viel umgestellt werden, läuft es genauso stabil?
 
Also noch mal wegen der Lizenzkosten: Oracle JDK 8 = kein Problem! Kannste verteilen, wird sich keiner dran stören.

Java 11 + OpenJFX 11 -> Grundsätzlich hat @Flown recht, kein Unterschied.

Aber:
Leider doch. Open JDK hat nie JavaFX enthalten. Mit OpenJFX 11 ist es recht easy geworden: Dependency hinzufügen und fertig (bitte mal auf https://openjfx.io nachlesen).

Jedoch:
Danke Java 9 hat sich von 8 zu 11 schon einiges geändert (Modulsystem, keine javapacker Ttool mehr integriert - kann man aber separat bekommen (siehe hier), ...).

Fazit: Einfach probieren! Stabilität wird kein Problem sein, im Gegenteil, es wurden Verbesserungen wie neuere WebKit-Engine etc. hinzugefügt.
 
Soweit ich weiß betrifft Oracles Wunsch, die Java-Orange auszupressen, nur Servergedöns.
Ich würde das anders sehen; mit Server/nicht Server hat das erstmal gar nichts zu tun (ja, die Preise sind anders).

Abstrakt betrachtet, hat sich eigentlich nichts geändert: man konnte schon immer zwischen unsupported (kostenlos) und supported (kostenpflichtig) wählen. Und das ist auch künftig so.

Die kostenlose Version wird jetzt unter dem Namen "Oracle OpenJDK" über andere Seiten (z. B. https://jdk.java.net/11/) verteilt, während die kostenpflichtige Variante "Oracle Java" heißt und auf der gewohnten Downloadseite von Oracle erhältlich ist.

Problematisch kann das lediglich bei Java 8 werden, denn während das Oracle JDK/JRE für Java 8 nach wie vor frei ist, fallen Updates, die ab Februar erscheinen, unter die neue Lizenz und sind somit kostenpflichtig, sobald sie im kommerziellen Umfeld zum Einsatz kommen. Das ist insofern nicht ganz ungefährlich, weil zeitgleich Updates für den Privatgebrauch kostenfrei bis 2020 erscheinen.

Was das allerdings mit Deinem Programm zu tun hat, erschließt sich mir nicht. Du stellst ja bis Java 8 in der Regel nicht das JDK/JRE zur Verfügung sondern nur Deine Anwendung. Welche Java-Implementierung der Anwender nutzt, um sie laufen zu lassen, ist sein Problem.

Falls Du doch ein Bundle anbietest, dürfte es völlig egal sein, ob Du ein Oracle Java 8 (bis u201/u202, die am 15. Januar erschienen sind) oder ein OpenJDK 8+JavaFX dazupackst.

Alles natürlich nur meine persönliche Sichtweise, ohne Anspruch auf Korrektheit :)
 
Vielen Dank...das ist doch schonmal ein kleiner Überblick.

Was das allerdings mit Deinem Programm zu tun hat, erschließt sich mir nicht. Du stellst ja bis Java 8 in der Regel nicht das JDK/JRE zur Verfügung sondern nur Deine Anwendung. Welche Java-Implementierung der Anwender nutzt, um sie laufen zu lassen, ist sein Problem.
Nun, ich würde dem Installationspaket durchaus eine JRE-Installation beilegen. In der Registry schauen ob Java installiert ist, wenn nicht wird das Java-Installationsprogramm ausgeführt. NSIS macht es ja sehr einfach.

Das macht es dem Benutzer halt einfach. (Jaja, typisch Windows-Nutzer... ;))
 
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben