Befüllung der einzelnen Zeilen des TableView

MattElg

Mitglied
Ich habe die Controllerklasse so gestaltet, dass es ein beliebiges SQL Statement an die Modell Klasse liefern soll, dieses soll daraus einen Array liefern, mit der ersten Zeile(Zeile0 im Array) als Spaltennamen. Dies klappt. Ich habe nun die auch Überschriften der Tabelle sichtbar gemacht. Direkt über den Array aus dem SQL Statement.
Was immer noch nicht klappt ist die Befüllung der einzelnen Zeilen des TableView.
Also das mit "setCellValueFactory(new Callback<CellDataFeatures" funktioniert da nichts mehr. Weder kann ich auf die TableView zugreifen, noch auf dessen Spaltennamen,
Ich möchte die einzelnen Zeilen befüllen, denn es sind ja mehrere Spalten, deren Anzahl ich ja nicht kenne, da der SQL Code flexibel sein soll.

Controllerklasse:

Code:
package ausgabe;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.TableColumn;
import model.DataBean6;
import eingabe.EingabeVC6;
import java.util.Arrays;

import ausgabe.AusgabeVC6.backBtnEventHandler;


public class Ausgabe {
    private DataBean6 dataBean;
    private AusgabeView6 view;
    private String sqlstate;
    //private ObservableList data;
    private ObservableList<String[]> data;
    private String[][] tabelle;
   
    public void AusgabeVC6(DataBean6 dataBean) {
        this.dataBean = dataBean;
        this.view = new AusgabeView6();
        // Eventhandler registrieren
        view.getBackBtn().setOnAction(new backBtnEventHandler());   
    }

    @SuppressWarnings("unchecked")
    public void show(){
       
        // View mit Daten befuellen
        //vertikal
        sqlstate = ("* from people;");
        tabelle = dataBean.getTabelle(sqlstate);       
       
    TableColumn[] tableColumns = new TableColumn[tabelle[0].length];
       
    for (int a = 0; a < tabelle[0].length; a++) {
        tableColumns[a] = new TableColumn(tabelle[0][a]);
        final int index = a ;
       
    }
    view.getTable().getColumns().addAll(tableColumns);
    System.out.println("Spaltenname: "+tableColumns[1]);
    //int zeile = 1 - da zeile 0 die Spaltennamen waren
    for (int zeile = 1; zeile < tabelle.length; zeile++) {
        for (int a = 0; a < tabelle[0].length; a++) {
            view.getTable().setCellValueFactory(new Callback<CellDataFeatures<String[], (tabelle[zeile][a])>>);
        }
    }
    i++;   
        view.show(dataBean.getPrimaryStage());
    }
   
    //+++++++++++++++++++++++++++++++++++++++++++++
    // Events
    //+++++++++++++++++++++++++++++++++++++++++++++

   
    class backBtnEventHandler implements EventHandler<ActionEvent>{

        @Override
        public void handle(ActionEvent e) {   
            // zur naechsten Seiten springen!
            EingabeVC6 eingabeVC = new EingabeVC6(dataBean);
            eingabeVC.show();  
        }
    }
}

Die View Klasse:
Code:
package ausgabe;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.TableView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**
* @author Matt
*
*/
public class AusgabeView6{
   
    private Scene scene;
   
    private GridPane grid;
    private Text scenetitle;
    //private ListView<String> list;   
    //private String[][] tabelle;
    //private TableView<String> list;   
    private TableView table;
   
    private Button backBtn;
    private HBox hbBtn;
   
    public AusgabeView6() {
        // Layout
        grid = new GridPane();
        grid.setAlignment(Pos.CENTER);
        grid.setHgap(10);
        grid.setVgap(10);
        grid.setPadding(new Insets(25, 25, 25, 25));

        // Ueberschrift
        scenetitle = new Text("Hallo");
        scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
        grid.add(scenetitle, 0, 0, 2, 1);

        // Tabelle
       table = new TableView();
        table.setEditable(true);
        table.setMinWidth(600);
        grid.add(table, 0,1);
      
       
        /*funktioniert
        list = new ListView<>();
        //list = new TableView<>();
        list.setMinWidth(200);
        grid.add(list, 0,1);
        */
        // Button
        backBtn = new Button("zurück");

        // Buttongruppe
        hbBtn = new HBox(10);
        hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
        hbBtn.getChildren().add(backBtn);
        grid.add(hbBtn, 0, 2);

        scene = new Scene(grid, 300, 300);
    }

    public void show(Stage stage) {
        stage.setTitle("JavaFX MVC Beispiel");
        stage.setScene(scene);
        stage.show();
    }

   public TableView getTable(){
        return table;
    }

    public Button getBackBtn() {
        return backBtn;
    }
}
 
Der Konstruktor der TableColumn nimmt die Spaltenbeschriftung entgegen, so wie du das glaube ich auch bereits hinbekommen hast.
Direkt nach der Instanziierung der TableColumn kannst du dieser mit

Java:
tableColumn.setCellValueFactory(row->{
    String wert = row.getValue()[deinspaltenindex];
     return new SimpleStringProperty(wert);
});

eine CellValueFactory zuweisen, die auf die Zeile zurückgreift und auf Spalte deinspaltenindex zugreift und als Stringproperty zurückliefert.
Gewöhne dir am Besten bei JavaFX die Verwendung von solchen Lambda-Ausdrücken wie ich sie jetzt verwendet habe an, damit machst du dir den Überblick wesentlich leichter.

Was auf jeden Fall noch fehlt ist, dass du deine Werte der Tabelle zuweist. Mithilfe von getColumns kriegst du die Spalten zurückgeliefert, mit getItems bekommst du die Liste der Datenobjekte der TableView zurück. Solch eine Zuweisung der Werte fehlt jedoch bei dir soweit ich das sehen kann.

Fliegen bei dir irgendwelche Exceptions oder welche Fehler bekommst du denn angezeigt?
 
bei der Zeile: "view.getTable().setCellValueFactory(new Callback<CellDataFeatures<String[], (tabelle[zeile][a])>>);"
zeigt Eclipse:
Multiple markers at this line
- Syntax error on token ",", TypeArgument2 expected after this token
- Syntax error on token ">>", Expression expected after this token
Also der akzeptiert es gar nicht.
Genau damit will ich ja die Werte der Tabelle zuweisen.

Die Spaltennamen konnte ich ja definieren:
TableColumn[] tableColumns = new TableColumn[tabelle[0].length];
for (int a = 0; a < tabelle[0].length; a++) {
tableColumns[a] = new TableColumn(tabelle[0][a]);
final int index = a ;
}
Das klappt ja, nun bekomme ich soviele Spalten angezeigt, wie in der SQL Formel drin sind. Wobei tableColumns[] nur ein Übergangsarray für die Spaltennamen ist, wie "id", "name", "firstname".

Aber ich weiß und fand keinen Weg, wie ich nun der Spalte "id", die Werte von dem Array tabelle zuweisen kann. Also alle Zeilen des Arrays tabelle[x][1].
Vielleicht bin ich nur zu dumm.
 
Ich bin noch meine Lösung schuldig. Also hier zum Nachtrag. Ich habe 7 Klassen, je 2 für Eingabe und Ausgabe, eines für die Connektion zu MySQL über Xampp, eines zur Datenbanknachfrage bzw. Speicherung neuer Eingabe in SQL und eine Starter-Klasse. Lacht bitte nicht, es sollte zur Einarbeitung für mich sein.
Starterklasse:
Code:
package main;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.stage.Stage;
import eingabe.EingabeVC8;
import model.DataBean8;

/**
* @author Matthias Elger
*/
public class Start8 extends Application {
    public static void main(String[] args) {
        launch(args);
    }
   
    @Override
    public void start(Stage primaryStage) throws Exception {
        try{
            // Sessionscope /Applikationscope Beans inizitalisieren!
            // muessen von Controllern weitergegeben werden
            DataBean8 dataBean = new DataBean8(primaryStage);
  
        // Ersten Controller aufrufen
        EingabeVC8 eingabeVC = new EingabeVC8(dataBean);
        eingabeVC.show(); 
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
      
}

Das View für die Eingabe:
Code:
package eingabe;

import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**
* @author Matthias Elger
*/
public class EingabeView8{
  
   private Scene scene;
  
   private GridPane grid;
   private Text scenetitle;
  
   private Label vornameLB;
   private TextField vornameTF;
  
   private Label nachnameLB;
   private TextField nachnameTF;
  
   private Text meldungT;
  
   private Button okBtn;
   private Button addBtn;
   private HBox hbBtn;
  
   public EingabeView8() {
     // Layout
     grid = new GridPane();
     grid.setAlignment(Pos.CENTER);
     grid.setHgap(10);
     grid.setVgap(10);
     grid.setPadding(new Insets(25, 25, 25, 25));

     // Ueberschrift
     scenetitle = new Text("Hallo!");
     scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
     grid.add(scenetitle, 0, 0, 2, 1);

     // Vorname
     vornameLB = new Label("Vorname:");
     grid.add(vornameLB, 0, 1);

     vornameTF = new TextField();
     grid.add(vornameTF, 1, 1);
    
     // Nachname
     nachnameLB = new Label("Nachname:");
     grid.add(nachnameLB, 0, 2);

     nachnameTF = new TextField();
     grid.add(nachnameTF, 1, 2);

     // Buttons
     addBtn = new Button("eintragen");
     okBtn = new Button("Alle anzeigen");

     // Buttongruppe
     hbBtn = new HBox(10);
     hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
     hbBtn.getChildren().add(addBtn);
     hbBtn.getChildren().add(okBtn);
     grid.add(hbBtn, 1, 4);

     // Meldung
     meldungT = new Text();
     grid.add(meldungT, 1, 6);

     scene = new Scene(grid, 300, 300);
   }

   public void show(Stage stage) {
     stage.setTitle("JavaFX MVC Beispiel");
     stage.setScene(scene);
     stage.show();
   }


   // nur Getter von Elementen anlegen, die veraendert werden und/oder dynamisch sind
   public TextField getVornameTF() {
     return vornameTF;
   }


   public TextField getNachnameTF() {
     return nachnameTF;
   }


   public Text getMeldungT() {
     return meldungT;
   }

   public Button getOkBtn() {
     return okBtn;
   }


   public Button getAddBtn() {
     return addBtn;
   }


}
Der Controller für die Eingabe:
Code:
package eingabe;

import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import model.DataBean8;
import ausgabe.AusgabeVC8;

/**
* Steuert alle Interaktionen der Eingabe-Maske
* Verbindet die View mit dem Model
*
* @author Matthias
*/
public class EingabeVC8 {
  
   // Model
   private DataBean8 dataBean;
  
   // View
   private EingabeView8 view;
  
  
   public EingabeVC8(DataBean8 dataBean) {
     this.dataBean = dataBean;
     this.view = new EingabeView8();
    
     // Eventhandler registrieren
     view.getAddBtn().setOnAction(new addBtnEventHandler());  
     view.getOkBtn().setOnAction(new OkBtnEventHandler());  
   }
  
   // Start2
   public void show(){
     view.show(dataBean.getPrimaryStage());
   }
  
   //+++++++++++++++++++++++++++++++++++++++++++++
   // Events
   //+++++++++++++++++++++++++++++++++++++++++++++

  
   class OkBtnEventHandler implements EventHandler<ActionEvent>{

     @Override
     public void handle(ActionEvent e) {  
       // zur naechsten Seiten springen!
       AusgabeVC8 ausgabeVC = new AusgabeVC8(dataBean);
       ausgabeVC.show();  
     }
    
   }
  
   class addBtnEventHandler implements EventHandler<ActionEvent>{

     @Override
     public void handle(ActionEvent e) {  
       // Meldung reseten
       view.getMeldungT().setText("");
      
       // Daten aus den Textfeldern holen
       String vname = view.getVornameTF().getText();
      String nname = view.getNachnameTF().getText();
      
       //Textfelder zuruecksetzen
       view.getNachnameTF().setText("");
       view.getVornameTF().setText("");
      
       // Daten testen
       if(vname.isEmpty()){
         view.getMeldungT().setText("Der Vorname fehlt!");
         return;
       }
       if(nname.isEmpty()){
         view.getMeldungT().setText("Der Nachname fehlt!");
         return;
       }
      
       // Daten hinzufuegen  - setter aufgerufen aus Databean
       dataBean.setNamePwMap(vname, nname);
      
       // Meldung ausgeben
       if(vname == null && nname == null){
         view.getMeldungT().setText("Leser bereits vorhanden");
       }else{
         view.getMeldungT().setText("Folgenden Leser hinzugefügt: " + vname + " " +nname);
       }
     }
  }
}
Die View für die Ausgabe:
Code:
package ausgabe;

import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListView;
import javafx.scene.control.TableView;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Stage;

/**
* @author Matthias Elger
*/
public class AusgabeView8{
  
   private Scene scene;
  
   private GridPane grid;
   private Text scenetitle;
   TableView<String[]> table;
   private Button backBtn;
   private HBox hbBtn;
  
   public AusgabeView8() {
     // Layout
     grid = new GridPane();
     grid.setAlignment(Pos.CENTER);
     grid.setHgap(10);
     grid.setVgap(10);
     grid.setPadding(new Insets(25, 25, 25, 25));

     // Ueberschrift
     scenetitle = new Text("Leser Übersicht");
     scenetitle.setFont(Font.font("Tahoma", FontWeight.NORMAL, 20));
     grid.add(scenetitle, 0, 0, 2, 1);

     // Liste
     table = new  TableView<String[]>();
     table.setEditable(true);
     table.setMinWidth(100);
     grid.add(table,1, 0, 2, 2);
      
     /*funktioniert auch
     list = new ListView<>();
     //list = new TableView<>();
     list.setMinWidth(200);
     grid.add(list, 0,1);
     */
     // Button
     backBtn = new Button("zurück");

     // Buttongruppe
     hbBtn = new HBox(10);
     hbBtn.setAlignment(Pos.BOTTOM_RIGHT);
     hbBtn.getChildren().add(backBtn);
     grid.add(hbBtn, 0, 2);

     scene = new Scene(grid, 300, 300);
   }

   public void show(Stage stage) {
     stage.setTitle("JavaFX MVC Beispiel");
     stage.setScene(scene);
     stage.show();
   }

   /*public ListView<String> getList() {
     return list;
   }*/
   public TableView getTable(){
     return table;
   }

   public Button getBackBtn() {
     return backBtn;
   }
}
Der Controller für die Ausgabe:
Code:
package ausgabe;

import javafx.beans.property.SimpleStringProperty;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.control.TableColumn;
import javafx.util.Callback;
import javafx.scene.control.TableColumn.CellDataFeatures;
import model.DataBean8;
import eingabe.EingabeVC8;
import java.util.Arrays;

/**
* Steuert alle Interaktionen der Ausgabe-Maske
* Verbindet die View mit dem Model
* @author Matthias Elger
*/
public class AusgabeVC8 {
  
   private DataBean8 dataBean;
   private AusgabeView8 view;
   private String sqlstate;
   ObservableList<String[]> data = FXCollections.observableArrayList();
   private String[][] tabelle;
   public AusgabeVC8(DataBean8 dataBean) {
     this.dataBean = dataBean;
     this.view = new AusgabeView8();
     view.getBackBtn().setOnAction(new backBtnEventHandler());  
   }
  
   /**
    * als ein Array aus SQL Tabelle mit getTabelle holen, dabei als Parameter den SQL Code, alles außer Select übergeben,
    * also * from Tabellenname oder name, vname from table where...
    * dies dann in einem TableView aus AusgabeView darstellen, das aufgerufen wirdm inkl. Button,...
    */
   @SuppressWarnings("unchecked")
   public void show(){  
     // View mit Daten befuellen
       sqlstate = ("* from people;");
       //an Array übergeben
       tabelle = dataBean.getTabelle(sqlstate);
       int rowLength = (tabelle.length);
       System.out.println("Zeilen Ausgabe"+rowLength);
       //spalten - ich muss oben bei remove von ArrayList die letzte Zeile entfernen, nicht die erste, die fehlt nämlich
    for(int i=0 ; i<tabelle[0].length; i++) {
       TableColumn col = new TableColumn(tabelle[rowLength-3][i]);
    final int colNo = i;
    col.setCellValueFactory(new Callback<CellDataFeatures<String[], String>, ObservableValue<String>>() {
    @Override
    public ObservableValue<String> call(CellDataFeatures<String[], String> p) {
    return new SimpleStringProperty((p.getValue()[colNo]));
    }
    });
    col.setPrefWidth(90);
    view.getTable().getColumns().add(col);
    //Megadaten auf null setzen
    tabelle[rowLength-3][i] = null; //Spaltennamen aus Array löschen
    tabelle[rowLength-2][i] = null;   // Typ aus Array löschen
    tabelle[rowLength-1][i] = null;   // Spaltenlänge aus Array löschen
    }
    //http://stackoverflow.com/questions/20769723/populate-tableview-with-two-dimensional-array/20774549
      
       System.out.println(view.getTable().getColumns().toString());
       view.getTable().setMinWidth(100);
       view.getTable();
       data.addAll(Arrays.asList(tabelle));
       System.out.println(data);
       view.getTable().getItems().addAll(data);
     //Doppelklick erkennen - später wichtig:
     //http://javawiki.sowas.com/doku.php?id=javafx:tableview-doubleclick-row
    
     /**
      *  View anzeigen
      */
     view.show(dataBean.getPrimaryStage());
   }
  
   //+++++++++++++++++++++++++++++++++++++++++++++
   // Events
   //+++++++++++++++++++++++++++++++++++++++++++++

   /**
    * Button zurück zur Eingabe springen
    */
   class backBtnEventHandler implements EventHandler<ActionEvent>{

     @Override
     public void handle(ActionEvent e) {  
       // zur naechsten Seiten springen!
       EingabeVC8 eingabeVC = new EingabeVC8(dataBean);
       eingabeVC.show();  
     }
    
   }
}
Die SQL Model - Klasse
Code:
package model;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Statement;
import java.util.ArrayList;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.stage.Stage;
import main.DBConnect;

/**
* Daten, die innerhalb der Anwendung gebraucht werden, werden in Beans gespeichert.
* Diese Klassen speichern nur Werte und haben keine andere Aufgabe!
*
* @author Matthias Elger
*/
public class DataBean8 {
  
     //private List<String> columns = new ArrayList<String>();
     private String[][] tabelle;
     private Stage primaryStage = null;
     private ObservableList<String> data;
    
   public DataBean8(Stage primaryStage)  {
     this.primaryStage = primaryStage;
     }
   /**
    * ermöglicht Eingabe von Werten
    */
   public void setNamePwMap(String vname, String nname) {  
     try{
       Connection con ;
       con = DBConnect.connect();
       Statement stt1 = con.createStatement();
       stt1.execute("USE test");
       String insert = ("INSERT INTO people (fname, lname) VALUES ('" + vname + "', '" + nname +"')");
       Statement stt2 = con.createStatement();
       stt2.execute(insert);          
     }
     catch (Exception e)
    {
    e.printStackTrace();
    }
   }
  
   /**
    * ermöglicht Ausgabe von SQL Tabelle, je nach SQL Anweisung, die übergeben wird
    * Ausggeben wird ein zweidimmensionales Array
    */
   public String[][] getTabelle(String sqlstate) {  
     try{
       Connection con ;
       con = DBConnect.connect();
       Statement stt1 = con.createStatement();
       stt1.execute("USE test");
       //String insert = ("Select * from people;");
       PreparedStatement prep = con.prepareStatement("Select "+ sqlstate);
    ResultSet rs = prep.executeQuery();
    //springt zur letzten Zeile im Resultset, gibt dann die Position aus,
    rs.last();
    int anzZeilen = rs.getRow();
    System.out.println(anzZeilen);
       ResultSetMetaData rsmd = rs.getMetaData();
       tabelle = new String[anzZeilen+3][rsmd.getColumnCount()];
       System.out.println("Anzahl Sätze: "+rs.getRow());
       int zeilen = 0;
       ObservableList<String> row = FXCollections.observableArrayList();
       String col = new String();
       rs.first();
       do {
  for (int i = 0; i < rsmd.getColumnCount(); i++) {
     col = rs.getString((i+1));
     tabelle[zeilen][i] = rs.getString((i+1));
     row.add(col);
  }
  zeilen ++;
  } while (rs.next());
      
       /**
        * hängt als vorvorletzte Zeile im Array die Spaltennamen mit
        * und als vorletzte Zeile den Typ, als letzte die Größe
        */
  for (int i = 0; i < rsmd.getColumnCount(); i++) {
         tabelle[anzZeilen][i] = rsmd.getColumnName(i+1);
         tabelle[anzZeilen+1][i] = rsmd.getColumnTypeName(i+1);
         //tabelle[anzZeilen+2][i]    = (rsmd.getCatalogName(i+1));
         int spaltensize = rsmd.getColumnDisplaySize(i+1);
         tabelle[anzZeilen+2][i] = toString().valueOf(spaltensize);
       }
       stt1.close();
    con.close();
     }
     catch (Exception e)
    {
    e.printStackTrace();
    }
     return tabelle;
   }
  
   public Stage getPrimaryStage() {
     return primaryStage;
   }
}
Der SQL Connectionklasse:
Code:
package main;

import java.sql.Connection;

   import java.sql.DriverManager;
   import java.sql.SQLException;

   /**
    * @author Matthias
    */

   public class DBConnect {

    private static Connection conn;
    /**
  * 3306 is the default port for MySQL in XAMPP. Note both the
  * MySQL server and Apache must be running.
  */
    private static String url = "jdbc:mysql://localhost:3306/";
    
    /**
  * The MySQL user.
  */
    private static String user = "root";
    
    /**
  * Password for the above MySQL user. If no password has been
  * set (as is the default for the root user in XAMPP's MySQL),
  * an empty string can be used.
  */
    private static String pass = "";

    public static Connection connect() throws SQLException{
    try{
       Class.forName("com.mysql.jdbc.Driver").newInstance();
    }catch(ClassNotFoundException cnfe){
    System.err.println("Error: "+cnfe.getMessage());
    }catch(InstantiationException ie){
    System.err.println("Error: "+ie.getMessage());
    }catch(IllegalAccessException iae){
    System.err.println("Error: "+iae.getMessage());
    }

    conn = DriverManager.getConnection(url,user,pass);
    return conn;

    }

    public static Connection getConnection() throws SQLException, ClassNotFoundException{

    if(conn !=null && !conn.isClosed())

    return conn;
    connect();
    return conn;
    }
   }
 

Zurück
Oben