Daten aus DB -> JTable aktualisieren klappt nicht

chrisUBER

Mitglied
Hi,

vor ein paar Wochen habe ich einen Thread eröffnet, indem es um die Anwendungs des Cardlayouts ging (Thread). Dank eurer Hilfe konnte ich das Problem lösen und es mMn auch relativ gut umsetzen :)

Ok, habe das nun kurz angesprochen, da dies vielleicht auch mit meinem aktuellen Problem zu tun hat (Code dazu kommt weiter unten).

Mein aktuelles Problem: Ich habe mir aus einem JTable einen kleine Kalender gebastelt. Dieser Kalender holt sich aus einer Embedded DB (h2) die vorliegenden Termine und gibt diese an den entsprechenden Tagen wieder. Bei Programmstart funktioniert dieses einwandfrei. Ich kann zwischen den Monaten hin- und herschalten und die aktuellen Tage werden aus der Datenbank entnommen und korrekt dargestellt.

Jetzt habe ich zum Test ein kleines Formular gebastelt (noch ohne Eingabekontrollen etc) um neue Termine hinzuzufügen. Sobald ich nun einen Termin hinzufüge, wird dieser in die Datenbank eingetragen (funktioniert), jedoch wird das JTable mit dem Kalender nicht aktualisiert. Erst bei Neustart des Programmes oder beim hin- und herschalten der Monate wird der neue Termin angezeigt.

Habe versucht das Tablemodel mit fireTableDataChanged() zu aktualisieren, auch JTable.repaint(), revalidate() haben keinerlei Wirklung gezeigt.

Um nicht mein kompletten Chaoscode (bin noch Anfänger und kriege das MVC Konzept nicht sauber umgesetzt) zu posten, schreibe ich erstmal nur die Stellen, die mir wichtig erscheinen. Am Ende schreibe ich nochmal, wo ich die Fehler vermuten würde.

Klasse Navi: erstellt Buttons zur Auswahl der Cards inkl. Eventlistener
Java:
public Navi(Content mainPanel) {
        
        this.mainPanel = mainPanel;

        this.setBorder(javax.swing.BorderFactory.createTitledBorder("Menü"));
        this.setLayout(new javax.swing.BoxLayout(this, javax.swing.BoxLayout.Y_AXIS));

        
        jButton1 = new javax.swing.JButton("Übersicht");
        jButton2 = new javax.swing.JButton("Veranstaltungen");


        jLabel1 = new JLabel();
        jLabel1.setVisible(false);

        jPanel1 = new JPanel();
       
        
        jButton1.addActionListener(this);
        jButton2.addActionListener(this);


        jButton1.setMaximumSize(new Dimension(150, 24));
        jButton2.setMaximumSize(new Dimension(150, 24));



     // In dieser Methode änderst du das anzuzeigende Panel
    // über die showPanel-Methode in mainPanel
    public void actionPerformed(ActionEvent e) {

        if(e.getActionCommand().equals("Übersicht"))
            mainPanel.showPanel("Overview");
 
        if(e.getActionCommand().equals("Veranstaltungen")) 
            mainPanel.showPanel("Events");
             
    }
  
}

Klasse Content: Setzt das Cardlayout und fügt Panels hinzu (Hier vermute ich evtl. einen Fehler)
Java:
public class Content  extends javax.swing.JPanel {

    private CardLayout cardLayout;
    public JPanel panel1, panel2, panel3, panel4, panel5, panel7;

    
    public Content() {


         //Panel für den Inhalt wird erstellt und mit CardLayout versehen
         cardLayout = new CardLayout();
         this.setLayout(cardLayout);

         //Es werden 3 Panels für den Inhalt erstellt (kann erweitert werden)
         panel1=new JPanel();
         panel2=new JPanel();

         //Panel "Karten" initialisieren
         panel1.add(new Overview());        //Panel: Übersicht
         panel2.add(new Events());          //Panel: Veranstaltungen


         //Karten dem Panel hinzufügen
         this.add(panel1,"Overview");
         this.add(panel2,"Events");

    }

    //gewählte Karte anzeigen
public void showPanel(String panel) {
         cardLayout.show(this, panel);
         
    }

Klasse Events: Um den Code kurz zu halten, poste ich hier nur die Events Klasse (Events wird über den Button Veranstaltungen aufgerufen. Es wird eine einfache JTable mit allen Terminen angezeigt)

Java:
public class Events extends javax.swing.JPanel  {

    DefaultTableModel model = new DefaultTableModel();
    JTable tab;
    
    /** Creates new form Events */
    public Events()  {
        initComponents();

        String query = "SELECT * from termine ORDER BY datum ASC";
        abfragen(query);        //SQL String an abfragen() übergeben
        myUpdate();
        setVisible(true);


   }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();

        setBorder(javax.swing.BorderFactory.createTitledBorder("Veranstaltungen"));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 434, Short.MAX_VALUE)
                .addContainerGap())
        );
    }// </editor-fold>                        

    private void abfragen(String query)
    {
        Connection conn = Connect.driver();         //Verbindung herstellen
        Statement stm = Communication.stm(conn);    //Statement mit Verbindung erstellen
        ResultSet rs = Communication.rs(query,stm); //SQL String sowie Statement an Resultset übergeben, query wird ausgeführt
        tableModelEvents(rs);                       //ResultSet wird ans TM übergeben
        
         try {
                conn.close();
         }
                catch(Exception error){error.printStackTrace();}

     }

    private void tableModelEvents(ResultSet rs)
    {
        
               
        //Tabellenkopf Überschriften
        String datum,bez,kunde,pers,raum,beginn;
        datum="Datum";
        bez="Bezeichnung";
        kunde="Kunde";
        pers="Personen";
        raum="Raum";
        beginn="Beginn";
    
        //Tabellenkopf Überschriften zu addColumn
        model.addColumn(datum);
        model.addColumn(bez);
        model.addColumn(kunde);
        model.addColumn(pers);
        model.addColumn(raum);
        model.addColumn(beginn);


        //Vektor der Überschriften erstellen und ans TM übergeben
        Vector vectorHead = new Vector();
        vectorHead.add(datum);
        vectorHead.add(bez);
        vectorHead.add(kunde);
        vectorHead.add(pers);
        vectorHead.add(raum);
        vectorHead.add(beginn);
        model.setColumnIdentifiers(vectorHead);


        //Ausgabe der Datensätze in Vektor. Inhalte werden ans TM übergeben
        try{
            while(rs.next())
            {

                
                SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy");
                String dateFormat = formatter.format(rs.getDate("datum"));
                String switchDate[] = dateFormat.split("\\.");
                System.out.println(switchDate[0]);                          //Kontrollausgabe
               

                Vector vectorData = new Vector();
                vectorData.add(dateFormat);
                vectorData.add(rs.getString("bezeichnung"));
                vectorData.add(rs.getString("kunde"));
                vectorData.add(rs.getString("personen"));
                vectorData.add(rs.getString("raum"));
                vectorData.add(rs.getString("beginn"));
                model.addRow(vectorData);

                
             }
        }
        catch(Exception error){error.printStackTrace();}


       }
 //##############################
    public final void myUpdate() {

        System.out.println("bla");

        try {
                
        tab = new JTable(model) {

           public boolean isCellEditable(int x, int y) {   //Zellen nicht editierbar
                return false;
            }
        };

        //Tabelleneigenschaften (Anordnung bzw. Größe cht änderbar)
        tab.setRowHeight(25);
        tab.getTableHeader().setResizingAllowed(false);
        tab.getTableHeader().setReorderingAllowed(false);
        tab.setShowHorizontalLines(true);
        tab.setShowVerticalLines(false);
        tab.getModel();
        jScrollPane1.setViewportView(tab);
                

        } catch (Exception error){ System.out.println(error); }

           }

    
    // Variables declaration - do not modify                     
    private javax.swing.JScrollPane jScrollPane1;
    // End of variables declaration                   

}

Klasse NewEvent: Dies ist einfach nur ein Testformular um neue Datensätze während der Laufzeit des Programmes einzufügen. Es gibt keine Eingabekontrollen oder Sonstiges (also darauf achten, was man eingibt)
Java:
public class NewEvent extends javax.swing.JPanel {

    String datum, bezeichnung, kunde, beginn, raum, dekoration, aufbaubeginn;
    Integer personen;
    Boolean sekt, bedienung, dj, anzahlung;


    private PreparedStatement psInsert = null;
    private Overview Overview = null;
    private Events Events = null;

    /** Creates new form NewEvent */
    public NewEvent() {
        initComponents();
    }

private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {                                         
    getValues();        // TODO add your handling code here:
    addEvent();

    }                                        

   public void getValues() {
       datum = jTextField1.getText();
       bezeichnung = jTextField5.getText();
       kunde = jTextField2.getText();
       beginn = jTextField4.getText();
       raum = jComboBox1.getSelectedItem().toString();
       personen = Integer.parseInt(jTextField3.getText());
       sekt = jCheckBox1.isSelected();
       bedienung = jCheckBox2.isSelected();
       dj = jCheckBox3.isSelected();
       anzahlung = jCheckBox4.isSelected();
       dekoration = jTextArea1.getText();
       aufbaubeginn = jTextArea2.getText();
  }

  public void addEvent() {
      try {

            Connection conn = Connect.driver();
            Statement stm = Communication.stm(conn);

            String sql = "INSERT INTO TERMINE (datum, bezeichnung, kunde, "
                    + "personen, raum, beginn, sekt, bedienung, dj, anzahlung, "
                    + "dekoration, aufbaubeginn) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
            psInsert = conn.prepareStatement(sql);
            psInsert.setString(1, datum);
            psInsert.setString(2, bezeichnung);
            psInsert.setString(3, kunde);
            psInsert.setInt(4, personen);
            psInsert.setString(5, raum);
            psInsert.setString(6, beginn);
            psInsert.setBoolean(7, sekt);
            psInsert.setBoolean(8, bedienung);
            psInsert.setBoolean(9, dj);
            psInsert.setBoolean(10, anzahlung);
            psInsert.setString(11, dekoration);
            psInsert.setString(12, aufbaubeginn);
            psInsert.executeUpdate();
                     
            conn.close();
            } catch(Exception e) {
               
                System.out.println(e);
            }
      
     

  }

Das wars erstmal vom Code, hoffe habe das nötigste nicht rausgelöscht (wollte halt nicht das Forum sprengen :))

Habe die ganzen fireTableDataChanged(), repaint() und revalidate() mal wieder rausgenommen. Habe diese Methoden zum Test echt überall mal eingefügt mit der Hoffnung, dass es irgendwann mal funktioniert.

Ich vermute nun den Fehler bei: 1. fireTable... repaint und revalidate werden an den falschen Stellen aufgerufen bzw. nicht korrekt ans Tablemodel übergeben oder 2. in der Klasse Content werden die Panels einmal aufgerufen (z.b. durch new Events();) und danach durch das Cardlayout nur angezeigt bzw. ausgeblendet. Die Klasse Events() wird also bei erneutem Aufruf nicht neu geladen bzw. aktualisiert sondern einfach nur wieder eingeblendet (mit den alten Daten).

Das Gleiche Problem besteht halt auch bei meiner Overview Klasse (dort ist das JTable als Kalender dargestellt).

Und mal wieder ist mein Post recht lang geworden. Wusste nicht, wie ich mein Problem genauer schildern soll. Habe auch schon im Internet und in diesem Forum nach ähnlichen Problemen gesucht, jedoch hat mir nichts wirklich geholfen.

Mein Code ist relativ chaotisch, besonders weil ich das MVC-Konzept in einigen andere Klassen gut umsetzen konnte und dann teilweise wieder doch nicht. Hoffe jedoch, dass meine Codeschnipsel verständlich sind.

Ich hoffe auf erneute Hilfe eurerseits und bedanke mich im Voraus.

Mit freundlichem Gruß

chris
 

Michael...

Top Contributor
Jetzt habe ich zum Test ein kleines Formular gebastelt (noch ohne Eingabekontrollen etc) um neue Termine hinzuzufügen. Sobald ich nun einen Termin hinzufüge, wird dieser in die Datenbank eingetragen (funktioniert), jedoch wird das JTable mit dem Kalender nicht aktualisiert. Erst bei Neustart des Programmes oder beim hin- und herschalten der Monate wird der neue Termin angezeigt.

Habe versucht das Tablemodel mit fireTableDataChanged() zu aktualisieren, auch JTable.repaint(), revalidate() haben keinerlei Wirklung gezeigt.
Woher soll die JTable bzw. deren Model denn wissen, dass in der Datenbank was neues drin steht? Wenn Du Änderungen an den Daten der DB vornimmst müssen die Daten eben erneut geladen werden (deswegen sind sie nach einem Hin- und Herschalten zu sehen)
Ist ja genauso wie wenn Du auf dem PC einen Brief schreibst und diesen ausdruckst. Wenn Du danach den Brief änderst bleibt ja der Ausdruck der selbe und man muss den Brief eben nochmals ausdrucken ;-)

Ich würde hier eventuell sogar anders herum vorgehen und die Einträge direkt der JTable hinzufügen bzw. darin editieren. An der JTable bzw. deren Model einen Listener hängen, der die Änderungen dann in die DB überträgt.
 

chrisUBER

Mitglied
Hmmm,

dann hab ich die Funktion vn fireTableDataChanged(); wohl falsch verstanden. Ich dachte immer, es reicht wenn ich nach dem Eintrag des Datensatzen in die DB dem Model einfach nur mit fireTableDataChanged klarmache, dass neue Daten vorliegen.

Dennoch verstehe ich dann die Lösung meines Problems immer noch nicht. In dem anderen Thread ist ja die Grafik abgebildet, wie mein Programm aufgebaut ist. Links das Menü, rechts werden die Daten dargestellt. Sobald ich nun über den Button die Klasse Events() aufrufe (mit Cardlayout show), wird diese Klasse doch komplett ausgeführt. In dieser Klasse ist doch eine SQL Abfrage über alle Daten vorhanden. Das bedeutet doch, dass sobald ich auf den Button klicke, die Klasse Events() aufgerufen wird -> eine neue SQL Abfrage gestartet wird (und diesmal mit neuem Datensatz) und daraufhin wieder im JTable dargestellt wird. Oder nicht? :)

Irgendwie ist bei mir der Wurm drin, mein Verständnis sagt mir, dass dies klappen sollte.. aber es klappt nicht :)

Wenn ich nun deinen Lösungsvorschlag umsetzen möchte, muss ich meinen kompletten Klassenaufbau ändern oder? Könnte Probleme mit der Klasse Overview geben, da ich mir dort echt viel zusammengebastelt habe (die ich hier nicht posten möchte, da sie einfach zu gross ist und ich mich für mein Chaos schäme :)). Falls sich einer mit meinem Problem auseinandersetzen möchte und es über das Forum nicht machbar ist, erstelle ich auch gerne eine Dokumentation für das komplette Projekt und schicke es per PM. Dies sollte jedoch nur die letzte Möglichkeit sein, da ich eigentlich recht ehrgeizig bin und es doch irgendwie alleine schaffen möchte :)

Danke schonmal für die Antwort

Gruß chris
 

Michael...

Top Contributor
dann hab ich die Funktion vn fireTableDataChanged(); wohl falsch verstanden. Ich dachte immer, es reicht wenn ich nach dem Eintrag des Datensatzen in die DB dem Model einfach nur mit fireTableDataChanged klarmache, dass neue Daten vorliegen.
Damit teilt das DefaultTableModel all seinen Beobachtern mit, dass sich das Datenmodell geändert hat. Das hat zunächst mal garnichts mit irgendwelchen Datenbanken zu tun. Es besteht ja keine automatische Bindung zwischen TableModel und Datenbank.
Sobald ich nun über den Button die Klasse Events() aufrufe (mit Cardlayout show), wird diese Klasse doch komplett ausgeführt. In dieser Klasse ist doch eine SQL Abfrage über alle Daten vorhanden. Das bedeutet doch, dass sobald ich auf den Button klicke, die Klasse Events() aufgerufen wird -> eine neue SQL Abfrage gestartet wird (und diesmal mit neuem Datensatz) und daraufhin wieder im JTable dargestellt wird. Oder nicht? :)
Sehe hier jetzt nichts von einem Button, sehe nur eine in der Klasse NewEvent eine Methode
Code:
jButton1ActionPerformed
die ja vermutlich von ActionListener eines Buttons aufgerufen wird.
Diese ruft wiederum zwei Methoden auf. Eine in der vom Anwender eingegeben Daten ausgelesen werden und eine die mit diesen Daten einen Eintrag in die Datenbank vornimmt...
... und mehr passiert nicht.

Wenn Du neue Daten in die Datenbank schreibst und diese dann gleich auch im TableModel haben willst, musst Du diese Daten erneut aus der Datenbank auslesen. Und das passiert bei Dir nicht (wäre ganz einfach mit einem
Code:
System.out.println("neue Daten werden ausgelesen");
an der richtigen Stelle zu überprüfen).
 

chrisUBER

Mitglied
Ah tut mir leid, habe vielleicht den Code zu viel gekürzt.

Versuche das nochmal kurz darzustellen:

Habe link ein Menü mit 3 Buttons (hab einen oben beim Code anscheinend gelöscht). Übersicht (Overview), Veranstaltungen (Events) und neueVeranstaltung (NewEvent). Diese werden, wie in der Klasse Content beschrieben, über das Cardlayout gewechselt. Bei Programmstart wird automatisch die Übersicht angezeigt. Habe also ausversehen den Button neueVeranstaltung und das dazugehörige panel3.add(new NewEvent()); gelöscht

Du hast natürlich recht, ich habe die Kontrollausgabe in die Klasse Events geschrieben (Hier ist halt eine Tabelle mit allen Terminen). Beim start des Programmes wird die Kontrollausgabe einmal ausgeben. Beim hin- und herschalten der Klassen Übersicht, Veranstaltungen und neueVeranstaltung wird beim Aufruf vom Panel Veranstaltungen die Kontrollausgabe NICHT noch einmal ausgegeben -> bedeutet für mich, hier ändert sich nichts bzw. wird nichts neu geladen. Also wäre doch die einfachste, aber vielleicht nicht schönste Lösung beim wechsel der Cards jedesmal die Klassen neu laden zu lassen. Ist das überhaupt möglich?

Dein Vorschlag mit dem JTable bzw. Model und Listener hört sich sehr gut an, ich habe jedoch Angst, dass das komplette Umbauen sehr zeitintensiv ist und ich am Ende garnicht mehr durchblicke.
 
Zuletzt bearbeitet:

Michael...

Top Contributor
Also wäre doch die einfachste, aber vielleicht nicht schönste Lösung beim wechsel der Cards jedesmal die Klassen neu laden zu lassen. Ist das überhaupt möglich?
Möglich schon Du könntest eine neue Komponente erzeugen und die alte ersetzen, wobei ....

Eigentlich müsstest Du ja nur die Methode
Code:
abfragen(String query)
erneut ausführen. Allerdings ist Deine Vorgehensweise beim Aufbau,Zusammenstellung und Befüllung des TableModels nicht gerade ideal und für einen wiederholten Aufruf geeignet. Mit Deiner Vorgehensweise müsstes Du ja jedesmal zunächst alle Spalten entfernen...
 

chrisUBER

Mitglied
Ja, ich seh gerade das mein nicht idealer Aufbau (sehr nett von dir ausgedrückt... mir wären schlimmere Sachen eingefallen :)) nur mehr Probleme bringt.

Oh man, wie kann ich das nun umbauen ohne den kompletten Projektordner wegzuschmeissen. Dachte echt ich bin auf dem richtigen Weg und man kann daraus noch was machen. Das größere Problem ist jedoch, dass bei den späteren Funktionen des Programmes ich wieder auf das gleiche Problem stoßen werde. Geplant ist noch eine kleine Bestandsverwaltung. Dort möchte ich direkt Werte im JTable editieren und diese sollen dann in die DB übergeben werden und diese natürlich auch direkt wieder ausgegeben haben.

Bin gerade echt am überlegen was ich nun mache, alles neu... oder irgendeine unschönere Lösung finden.

Habe nun versucht beim Einfügen eines neuen Datensatzes (NewEvent) das panel2 (für die Veranstaltungen) neu zu erzeugen und an die Klasse Content zu übergeben. In der Klasse Events habe ich am Ende der abfragen(String query) methode geschrieben, dass die tabelle neugezeichnet werden soll. Funktioniert leider auch nicht, es kommt zwar keinerlei Fehlermeldung, die Kontrollausgabe wird erneut aufgerufen, die Tabelle ist jedoch immer noch die alte.

Habe mich generell beim erstellen der Tabelle und des Models sowie die Übergabe der SQL Statements an ein Javatutorial von Video2Brain gehalten. Scheint anscheinend in der Praxis nicht umsetzbar zu sein auf andere Projekte.

Du wirst wahrscheinlich bemerken, dass ich so langsam verzweifel :) Kämpfe damit nun ganze 4 Tage, an einer eigentlich kleinen Sache.

Gruß chris
 

Michael...

Top Contributor
Für's erste sollte es mal reichen die Erstellung und Befüllung des TableModels zu optimieren.
Wenn Du bei Vector bleiben willst, kannst Du ja beim Auslesen des ResultSets einen verschachteltes Vector Objekt verwenden und das Model mit
Code:
model.setDataVector(Vector dataVector, Vector columnIdentifiers)
befüllen.


Hier mal ein paar Codeschnippsel. Dabei wird allerdings ein eigenes TableModel (basierend auf dem DefaultTableModel) verwendet, das die Daten intern als
Code:
ArrayList<String[]>
hält. Das geht sicher noch schöner und objektorientierter, sollte aber für den Anfang genügen.
Mit der Methode initModel wird das TableModel einmalig erstellt, die Methode fillModel wird zum Befüllen des Models verwendet und müsste in Deinem Fall nach jeden Speichern in die Datenbank neu aufgerufen werden.
Java:
public class TabModel {
	private MyTableModel model;
	
	public void initModel() {
		model = new MyTableModel(new String[] {"Datum", "Bezeichnung", "Kunde", "Personen", "Raum", "Beginn"}, 0);
	}
	
	
	public void fillModel() throws SQLException {
		ArrayList<String[]> newValues = new ArrayList<String[]>();
        SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy");
		
        //ResultSet ausführen
		ResultSet rs = null; 
		
		while(rs.next()) {
			String[] rowData = new String[6];
			rowData[0] =  formatter.format(rs.getDate("datum"));
			rowData[1] =  rs.getString("bezeichnung");
			...
			newValues.add(rowData);
		}
		System.out.println(newValues.size() + " Datensaetze aus der DB geladen");
		
		//aktualisieren des TableModels
		model.updateData(newValues);
	}
	
	class MyTableModel extends DefaultTableModel {
		private ArrayList<String[]> model;
		
		public MyTableModel(String[] strings, int rows) {
			super(strings, rows);
			model = new ArrayList<String[]>();
		}

		public void updateData(ArrayList<String[]> newModel) {
			this.model = newModel;
			fireTableDataChanged();
		}

		public int getColumnCount() {
			return 6;
		}

		public int getRowCount() {
			if (model==null)
				return 0;
			return model.size();
		}

		public Object getValueAt(int rowIndex, int columnIndex) {
			if (rowIndex >= 0 && rowIndex<model.size()) {
				String[] rowValues = model.get(rowIndex);
				if (columnIndex>=0 && columnIndex < rowValues.length)
					return rowValues[columnIndex];
			}
			return null;
		}
	}
}
 

chrisUBER

Mitglied
Danke schonmal für deine Hilfe. Find ich echt super, dass mir damit jemand hilft.

Habe nun eine neue Klasse erstellt (TabModel) und das rowData genau angepasst sowie die imports eingefügt. Der Kompiler meckert schonmal nicht, sehr gut. Bin mittlerweile echt durcheinander, wie bzw. wo füge ich denn jetzt die Befehle ein, damit diese Klasse aufgerufen wird und mein JTable von der Klasse NewEvent() dem neuem Model zugewiesen wird?

Deinen Code ansich habe ich verstanden (hoffe ich :)) und ist auch einleuchtend für mich. Wie baue ich diesen jedoch richtig ein? Nachdem ich in NewEvent() auf speichern klicke, soll die Methode initModel, sovie fillModel ausgeführt werden und danach dem JTable in der Klasse Events() zugeordnet werden. Richtig? Oder bewege ich mich schon wieder in die falsche Richtung?

Gruß chris
 
B

bERt0r

Gast
Du weist nicht dem Model einen Table zu, du weist einem Table ein Model zu: JTable.setModel(TableModel dataModel)
 

chrisUBER

Mitglied
Ah sorry, meinte ich auch so :) hab mich falsch ausgedrückt

Ok habe nun deinen Codeschnipsel übernommen und in meine Klasse Events eingefügt. Das neue Tablemodel wird auch richtig in der neuen GUI angezeigt. Bin also quasi nun wieder bei meinem Anfangsproblem, nur die Sache mit dem Tablemodel ist nun schöner gelöst. Jedoch ist nun auch hier wieder das Problem, dass sich das JTable nicht aktualisiert.

Ich zeig mal, wie ich den Codeschnipsel bei mir eingesetzt habe. Falls ich das komplett falsch verstanden habe, bitte meckern :)

Java:
public class Events extends javax.swing.JPanel  {
    
    private MyTableModel model;
    private JTable tab;

    /** Creates new form Events */
    public Events()  {


        initComponents();


        initModel();        //Model initialisieren

        tab = new JTable();
        tab.setModel(model);
        JScrollPane scrollPane = new JScrollPane(tab);
        tab.setFillsViewportHeight(true);
        jScrollPane1.setViewportView(tab);
        tab.repaint();
        

        try {
            fillModel();        //Model füllen
         }  catch(Exception e) {
                System.out.println(e);
         }

        setVisible(true);
   }
    
   public void initModel() {
        model = new MyTableModel(new String[] {"Datum", "Bezeichnung", "Kunde", "Personen", "Raum", "Beginn"}, 0);
    } 


    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">                          
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();

        setBorder(javax.swing.BorderFactory.createTitledBorder("Veranstaltungen"));

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
        this.setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 574, Short.MAX_VALUE)
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 434, Short.MAX_VALUE)
                .addContainerGap())
        );
    }// </editor-fold>                        

    public void fillModel() throws SQLException {
        ArrayList<String[]> newValues = new ArrayList<String[]>();
        SimpleDateFormat formatter = new SimpleDateFormat("dd.MM.yyyy");
       
        //ResultSet ausführen
        String query = "SELECT * from termine ORDER BY datum ASC";
        Connection conn = Connect.driver();         //Verbindung herstellen
        Statement stm = Communication.stm(conn);    //Statement mit Verbindung erstellen
        ResultSet rs = Communication.rs(query,stm); //SQL String sowie Statement an Resultset übergeben, query wird ausgeführt

        while(rs.next()) {
            String[] rowData = new String[6];
            rowData[0] =  formatter.format(rs.getDate("datum"));
            rowData[1] =  rs.getString("bezeichnung");
            rowData[2] = rs.getString("kunde");
            rowData[3] = rs.getString("personen");
            rowData[4] = rs.getString("raum");
            rowData[5] = rs.getString("beginn");
            newValues.add(rowData);
        }
        System.out.println(newValues.size() + " Datensaetze aus der DB geladen");

        //aktualisieren des TableModels
        model.updateData(newValues);
        }

    class MyTableModel extends DefaultTableModel {
        private ArrayList<String[]> model;

        public MyTableModel(String[] strings, int rows) {
            super(strings, rows);
            model = new ArrayList<String[]>();
        }

        public void updateData(ArrayList<String[]> newModel) {
            this.model = newModel;
            fireTableDataChanged();
            System.out.println("Kontrollausgabe fireTableDataChanged");   //Diese Ausgabe funktioniert. Also wird die Methode anscheinend aufgerufen. Jedoch keine Änderung im JTable
        }

        public int getColumnCount() {
            return 6;
        }

        public int getRowCount() {
            if (model==null)
                return 0;
            return model.size();
        }

        public Object getValueAt(int rowIndex, int columnIndex) {
            if (rowIndex >= 0 && rowIndex<model.size()) {
                String[] rowValues = model.get(rowIndex);
                if (columnIndex>=0 && columnIndex < rowValues.length)
                    return rowValues[columnIndex];
            }
            return null;
        }
    }

Die Daten werden erfolgreich aus der Datenbank aufgerufen und im JTable angezeigt. Bei Eintragung eines neuen Datensatzes über NewEvent() wird der Datensatz, bei erneutem Aufruf von Veranstaltungen (Events()), nicht angezeigt.

Du sagtest, ich muss nach dem Eintragen eines neuen Datensatzes nur die Methode fillModel() aufrufen. Wo genau sollte ich diese denn bei meinem Beispiel tun? In meiner Navi bzw. Content Klasse? Oder ist diese Richtung komplett falsch? Bin leider immer noch ein wenig überfragt :(

Der Aufbau dieses Tablemodels gefällt mir aber sehr gut, werde meine Overview Klasse auch umbauen. Habe das leider alles anders gelernt, teilweise auch sehr amateurhaft. Muss ich nun alles aufarbeiten :)

Morgen... :) Gute Nacht

Gruß chris

*Edit

Hallo, melde mich mit einem kleinen Update. Ich habe nun bei meiner Klasse Events zum Test einen JButton eingefügt. Bei Click dieses Buttons wird die Methode fillModel() nochmal aufgerufen... und siehe da, die Tabelle wird sofort aktualisiert und der neue Datensatz wird angezeigt. Aaaalso scheint für mich, als Leihe, der Fehler doch irgendwo beim Cardlayout zu liegen. Denn beim wechseln der Cards bzw. Panels wird die Tabelle nicht aktualisiert.
 
Zuletzt bearbeitet:

Michael...

Top Contributor
Hallo, melde mich mit einem kleinen Update. Ich habe nun bei meiner Klasse Events zum Test einen JButton eingefügt. Bei Click dieses Buttons wird die Methode fillModel() nochmal aufgerufen... und siehe da, die Tabelle wird sofort aktualisiert und der neue Datensatz wird angezeigt. Aaaalso scheint für mich, als Leihe, der Fehler doch irgendwo beim Cardlayout zu liegen. Denn beim wechseln der Cards bzw. Panels wird die Tabelle nicht aktualisiert.
Warum auch. Das CardLayout steuert ja nur die Anzeige der Komponenten - nicht mehr und nicht weniger.
Du musst unmittelbar, nachdem die neuen Daten in die Datenbank geschrieben wurden direkt oder indirekt die filllModel() aufrufen.
 

chrisUBER

Mitglied
Hallo,

habe nun in der Klasse NewEvent bei den Variablen Events events = new Events(); eingefügt und hinter psInsert.executeUpdate(); (Zeile 60) events.fillModel(); ausgeführt.

Eine Fehlermeldung kommt nicht, die Kontrollausgaben in der Methode updateData() werden bei jedem Einfügen eines neuen Datensatzen erneut ausgegeben. Das JTable aktualisiert sich jedoch leider immer noch nicht. Es funktioniert nur, wenn ich die Klasse Events aufrufe (also die Tabelle sehe) und dann auf meinen seperaten "aktualisieren" (den ich zum Test gemacht habe) button Button klicke.

Ich seh den Unterschied bei dem Vorgang halt nicht. Liegt der Fehler bei der Art wie ich die Methode aufrufe? Sobald ich die Methode in der Klasse Events aufrufe (durch den Button), funktioniert es einwandfrei. Sobald ich die Methode über die Klasse NewEvent aufrufe, kommt zwar keine Fehlermeldung aber es passiert auch nichts. Ich muss die Tabelle also quasi immer "manuell" durch klick aktualisieren

Gruß chris
 
Zuletzt bearbeitet:

Michael...

Top Contributor
habe nun in der Klasse NewEvent bei den Variablen Events events = new Events(); eingefügt und hinter psInsert.executeUpdate(); (Zeile 60) events.fillModel(); ausgeführt.
Da ich den aktuellen Aufbau nicht kenne, nur eine Vermutung: Das wird nicht viel bringen, da das neu erstellte Events Objekt (Vermutung jedes Events Objekt enthält ein eigenens TableModel) ja nichts mit dem auf der GUI angezeigten Events Objekt zu tun hat.
Und wie Dein Versuch mit dem Button zeigt, würde ein einfacher Aufruf von fillModel() die Ansicht der JTable aktualisieren. ==> einfach im Zuge der Datenaktualisierung in NewEvents die fillModel() aufrufen. Dazu muss aber auch das "DrumHerum" bzw. der Klassenaufbau stimmen bzw. der richtige "Referenzfluss" vorhanden sein d.h. das NewEvents Objekt muss eine Referenz auf das richtige Events Objekt besitzen bzw. auf das Objekt mit der Methode fillModel().

Falls doch eine Änderung des Klassen Designs in Frage kommt:
Ein dafür interessantes Entwurfsmuster: MVC
 

chrisUBER

Mitglied
Genau das ist das Problem.... das Event Objekt, welches auf der GUI angezeigt wird, kriege ich nicht aktualisiert nachdem ich einen Datensatz hinzugefügt habe.

Ich werde mich nun nochmal an dem MVC Konzept versuchen. Habe mich damit schonmal beschäftigt und einige Dinge klappten auch wie ich es mir vorgestellt habe. Aber nach einer Weile war der Code-Misch-Masch dann jedoch wieder da. Manchmal garnicht so einfach umzusetzen :) Werde mich dann heute Nacht damit auseinander setzen und versuchen die Datensatzeingabe mit dem MVC-Komzept zu realisieren.

Wäre es evtl. möglich dir mein komplettes Projekt zu schicken (Sind rund 10 Klassen inkl. Oberflächen mit Kommentierung)? Ich möchte natürlich nicht, dass du mir den Code fertig schreibst, will ja selbst etwas lernen :). Mich würde halt nur die Meinung eines erfahrenen Programmierers interessieren, ob es sich lohnt dieses Projekt auf diesem Weg weiterzumachen oder ob ich von neu anfangen sollte. Evtl. siehst du ja dann auch direkt den Fehler bzgl. meines Problems. Ist natürlich nur eine Bitte, falls du keine Lust oder Zeit dazu hast verstehe ich das.

Ich bedanke mich jedoch schonmal bei dir für die vielen Antworten, bin durch dich sehr viele Schritte voran gekommen (naja oder durch meine schlechte Vorarbeit halt auch wieder nach hinten :D).

Melde mich heute Nacht mit einem hoffentlich positiven Ergebnis.

Gruß chris
 

Michael...

Top Contributor
Ich werde mich nun nochmal an dem MVC Konzept versuchen. Habe mich damit schonmal beschäftigt und einige Dinge klappten auch wie ich es mir vorgestellt habe. Aber nach einer Weile war der Code-Misch-Masch dann jedoch wieder da.
Aber genau diesen "Code-Misch-Masch" sollte das MVC ja verhindern ;-)
Wäre es evtl. möglich dir mein komplettes Projekt zu schicken (Sind rund 10 Klassen inkl. Oberflächen mit Kommentierung)?
Kannst Du gerne machen, nur versprechen kann ich nichts, da es bei uns in dieser Woche ziemlich heiß hergeht...
 

chrisUBER

Mitglied
Also am Ende hat es doch so geklappt, wie ich es mir vorgestellt habe. Der Code ansich ist immer noch nicht der schönste, jedoch läuft nun alles so, wie es soll :)

Habe versucht das MVC Prinzip umzusetzen und der Einsatz von Observern hat mein Problem endlich gelöst. MVC ist noch ausbaufähig :D aber was läuft das läuft :) Bis zum nächsten Problem :)

Ich bedanke mich vielmals, tolles Forum. Bin hier fast den ganzen Tag am lesen und lernen :)

Gruß chris
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
L Swing Daten in JTable aktualisieren AWT, Swing, JavaFX & SWT 5
F JTable Daten aktualisieren AWT, Swing, JavaFX & SWT 2
D MySQL Daten in JTable anzeigen AWT, Swing, JavaFX & SWT 2
A JTable mit Daten füllen AWT, Swing, JavaFX & SWT 1
C Swing Daten in JTable wiedergeben per TableModel und MVC Pattern AWT, Swing, JavaFX & SWT 16
I JTable: Doppelklick auf Table soll neues Fenster öffnen und Daten aus JTable anzeigen AWT, Swing, JavaFX & SWT 4
S JTable Daten aus Array AWT, Swing, JavaFX & SWT 9
B Swing JTable mit Daten - Reihen-Größe anpassen AWT, Swing, JavaFX & SWT 0
F Swing JTable: Daten voreinstellen AWT, Swing, JavaFX & SWT 4
B Daten in eine JTable schreiben AWT, Swing, JavaFX & SWT 3
D Daten von JDialog an JTable in JFrame übergeben AWT, Swing, JavaFX & SWT 7
O JTable zeigt die alte Daten wieder AWT, Swing, JavaFX & SWT 23
H JTable zeigt keine Daten an AWT, Swing, JavaFX & SWT 5
C Swing JTable Daten einfügen AWT, Swing, JavaFX & SWT 6
Ollek IndexOutOfBoundsException bei neuen Daten in JTable AWT, Swing, JavaFX & SWT 13
J Swing JTable-Daten Speichern und bei zeilen-änderung beibehalten. AWT, Swing, JavaFX & SWT 6
T Daten mittels ComboBox in ein JTable adden AWT, Swing, JavaFX & SWT 7
Ollek Realisierung: JTable zur Laufzeit mit neuen Daten füllen AWT, Swing, JavaFX & SWT 3
GianaSisters Swing jTable Daten unsichtbar AWT, Swing, JavaFX & SWT 12
D Problem mit JFileChooser -> Daten werden mit anführungsstriche in JTable geschrieben AWT, Swing, JavaFX & SWT 8
S Swing Daten aus Datenbank in JTable AWT, Swing, JavaFX & SWT 2
L Daten werden in JTable nicht angezeigt:( AWT, Swing, JavaFX & SWT 6
J Daten in JTable nach Sortierung auslesen AWT, Swing, JavaFX & SWT 2
hdi Swing JTable & Filtern: Daten nicht in der View AWT, Swing, JavaFX & SWT 2
S JTable Bug - eingegebene Daten werden falsch geparst :( AWT, Swing, JavaFX & SWT 4
hdi Swing JTable: Löschen vom Daten im Model AWT, Swing, JavaFX & SWT 7
U JTable mit Daten aus einer HashMap füllen AWT, Swing, JavaFX & SWT 8
R JTable für sehr viele Daten sehr langsam AWT, Swing, JavaFX & SWT 20
B JTable: Wie speichert man manuell eingegebene Daten ausTable AWT, Swing, JavaFX & SWT 2
A JTable Vector mit Daten Ordnen bei setAutoCreateRowS AWT, Swing, JavaFX & SWT 8
S JTable Daten bearbeiten und Grauwertbild erzeugen! AWT, Swing, JavaFX & SWT 4
R Daten in JTable in mehreren Zeilen darstellen AWT, Swing, JavaFX & SWT 11
C JTable fehlende Daten AWT, Swing, JavaFX & SWT 2
raptorrs Daten aus JTable in JTextField übertragen AWT, Swing, JavaFX & SWT 11
G JTable Daten auslesen AWT, Swing, JavaFX & SWT 2
M JTable alte Daten vor Änderung abfangen AWT, Swing, JavaFX & SWT 11
O JTable mit objekt-daten füllen AWT, Swing, JavaFX & SWT 4
M Auslesen veränderter Daten in einer jTable AWT, Swing, JavaFX & SWT 2
J jTable Daten werden nicht sofort sichtbar AWT, Swing, JavaFX & SWT 5
G JTable dynamische Darstellung der ankommenden Daten AWT, Swing, JavaFX & SWT 19
vogella JTable - Hinzufügen von Datensätzen und Ändern von Daten AWT, Swing, JavaFX & SWT 2
D JTable und ungültige Daten AWT, Swing, JavaFX & SWT 2
F JTable Daten übernehmen AWT, Swing, JavaFX & SWT 2
D Daten über Button-Druck in JTable einfügen AWT, Swing, JavaFX & SWT 7
R nur bestimmte Daten in JTable anzeigen lassen? AWT, Swing, JavaFX & SWT 3
L JTable und Daten aus einer ArrayList AWT, Swing, JavaFX & SWT 6
D JTable zum Einfügen/Löschen/Editieren von Daten AWT, Swing, JavaFX & SWT 5
J JTable / Model Daten verändern AWT, Swing, JavaFX & SWT 5
M JTable zeigt daten nicht aktuell an AWT, Swing, JavaFX & SWT 4
C Dynamisches Zuweisen von Daten an eine JTable zur Laufzeit AWT, Swing, JavaFX & SWT 4
L Checkbox in JTable (again), bei true Daten in Header AWT, Swing, JavaFX & SWT 7
G Problem mit JTable / mit dem Eintragen der Daten aus Vector AWT, Swing, JavaFX & SWT 4
R JTable mit Daten aus der Datenbank füllen AWT, Swing, JavaFX & SWT 3
V Daten ins JTable laden bei Start der GUI AWT, Swing, JavaFX & SWT 6
M Daten aus Datenbank ins JTable einfügen AWT, Swing, JavaFX & SWT 4
V Daten im JTable speichern AWT, Swing, JavaFX & SWT 11
G JTable daten auslesen AWT, Swing, JavaFX & SWT 6
M Daten in JTable aus DB schreiben ? AWT, Swing, JavaFX & SWT 16
H Daten aus einer JTable in einer Datei speichern AWT, Swing, JavaFX & SWT 10
D Merken, daß Daten in der JTable sich geändert haben... AWT, Swing, JavaFX & SWT 2
L Daten mittels ObjectInputStream ins JTable AWT, Swing, JavaFX & SWT 7
H JTabel - RowFilter Daten für Berechnung filtern AWT, Swing, JavaFX & SWT 6
M Daten zufällig Einlesen aus einer Datei (binäres Format) AWT, Swing, JavaFX & SWT 7
W Nullpointer Exception beim übertragen von Daten von Scene zu Scene AWT, Swing, JavaFX & SWT 6
W Daten von Controller zu Controller übertragen AWT, Swing, JavaFX & SWT 7
D Columns unabhängig voneinander mit Daten füllen JavaFx AWT, Swing, JavaFX & SWT 1
H Daten aus einer XML(x83-Datei) in einem JFrame anzeigen lassen AWT, Swing, JavaFX & SWT 9
T Anbinden der Tabelle an die Daten AWT, Swing, JavaFX & SWT 5
F JavaFX Tabelle mit Daten füllen AWT, Swing, JavaFX & SWT 9
A JavaFX Daten in eine HTML-Table mit JS schreiben AWT, Swing, JavaFX & SWT 3
ralfb1105 JavaFX Daten zwischen Controllern austauschen- neue Frage AWT, Swing, JavaFX & SWT 7
ralfb1105 JavaFX Daten zwischen Controller "austauschen" AWT, Swing, JavaFX & SWT 65
B AWT Bot um Daten auf Website einzugeben und die Antwort zu bekommen AWT, Swing, JavaFX & SWT 2
L Daten bearbeiten ohne GUI zu blockieren - daten haltung/zurück geben AWT, Swing, JavaFX & SWT 15
ralfb1105 Swing JComboBox update der Daten AWT, Swing, JavaFX & SWT 8
ralfb1105 Swing Dynamischer Graph zum anzeigen Perfomance Daten AWT, Swing, JavaFX & SWT 35
K TreeTableView (cellFactory) - wie Daten in Spalten einfügen AWT, Swing, JavaFX & SWT 0
J TableView Daten werden nicht ausgegeben AWT, Swing, JavaFX & SWT 9
A Swing Wie Daten in der Form speichern? Array oder ArrayList AWT, Swing, JavaFX & SWT 2
T JavaFX Model Daten übergeben AWT, Swing, JavaFX & SWT 4
D Swing Größe einer JComboBox im GridBagLayout aufgrund der maximalen Länge der enthaltenen Daten AWT, Swing, JavaFX & SWT 7
J JavaFX Tableview Daten hinzufügen aus anderer Klasse AWT, Swing, JavaFX & SWT 7
J Tableview Daten hinzufügen und aktualisieren AWT, Swing, JavaFX & SWT 5
S AWT Daten über TextField und Button in array speichern AWT, Swing, JavaFX & SWT 5
G Event Handling TableView daten in ein neues Fenster herauslesen? AWT, Swing, JavaFX & SWT 3
S JavaFX (Best Practise) Daten zwischen Controllern austauschen AWT, Swing, JavaFX & SWT 1
thet1983 JavaFX TableView Objekt Daten anzeige AWT, Swing, JavaFX & SWT 2
L JavaFX Verzögerung beim Laden von Daten AWT, Swing, JavaFX & SWT 6
L Daten in neuem Fenster AWT, Swing, JavaFX & SWT 2
Tort-E JavaFX Daten an WebView Komponente AWT, Swing, JavaFX & SWT 1
M Java FX Daten an Controller übergeben AWT, Swing, JavaFX & SWT 3
S JList ist leer, aber DefaultListModel hat die Daten? AWT, Swing, JavaFX & SWT 9
M JavaFX Von FXML-Controllerdatei Daten zurückgeben AWT, Swing, JavaFX & SWT 6
F JavaFX Daten aus Tabelle in ComboBox AWT, Swing, JavaFX & SWT 9
D Applet GWT speichert Daten nicht in Datenbank AWT, Swing, JavaFX & SWT 2
S SWT In Listen den Einträgen Daten zuordnen AWT, Swing, JavaFX & SWT 2
T SWT Table (mit Spinner Spalte) Daten auslesen AWT, Swing, JavaFX & SWT 4
H Swing JfreeChart aktualisieren - mit daten aus thread AWT, Swing, JavaFX & SWT 3
J valueChanged()-Methode liefert unbrauchbare Daten AWT, Swing, JavaFX & SWT 4
B Datenübergabe zwischen Tabs und Daten speichern AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben