AbstractTabelModel

B

bmwGTR

Gast
Hallo liebe Forumsmitglieder,
Die Daten aus einer Datenbanktabelle möchte ich gerne in einer JTable darstellen.
ich lese gerade die Daten aus einer Datenbank und diese werden in einem String Vector gespeichert. Diesen Vector schicke ich wenn ich das AbstractTableModel erzeuge auch mit.

Das Lesen:
Java:
while(res.next())
{                
   for(int i = 1; i<=sp;i++)
   {
      daten.add(res.getString(i));
   }
}

Nun zu meiner Frage:
Wie kann ich am besten das getValueAt vom AbstractTableModel implementieren? Beim getValueAt werden ja rowIndex und columnIndex mitgesendet, nur da die Daten im Vector von links nach rechts gespeichert sind, habe ich keine Ahnung wie ich das implementieren könnte.

Vielen Dank für eure Hilfe. :)

mfg
bmwGTR
 

Marco13

Top Contributor
Du musst wissen, wie viele Zeilen/Spalten die Daten haben, die in dem Vector stehen, und ob die Daten zeilen- oder spaltenweise ("Row Major" oder "Column Major") abgelegt sind.
Java:
Object getValueAt(int r, int c)
{
    return vector.get(r*columns+c);
}

//bzw.

Object getValueAt(int r, int c)
{
    return vector.get(c*rows+r);
}
 
B

bmwGTR

Gast
Erstmal Danke für die schnelle Hilfe.

Also mal zum Beispiel:

Datenbank:
Vorname Nachname Instrument
Max Mustermann Tuba

Im Vector steht dann:
Max
Mustermann
Tuba

Und das hätte ich dann gerne in einer JTable dargestellt (also gleich wie in der Datenbank).
Welches muss ich jetzt nehmen?

mfg und vielen Dank für die rasche Hilfe
bmwGTR
 

Paxi

Mitglied
Du definierst erstmal ein DefaultTableModel für deinen Table.
Danach fügst du dem Model mit addColumn() die SpaltenNamen hinzu, die du entweder als Array oder Vector übergeben kannst.
Danach fügst du dem Model mit addRow() Zeile für Zeile dein Resultset hinzu, das du ebenfals als Vector oder 2-dim Array übergeben kannst siehe Doc.
Kann dir am abend noch einen Samplecode posten, habs jz gerade nur mal schnell ausm Kopf beantwortet.
 
B

bmwGTR

Gast
Danke für eure Hilfe :)

Also die Lösung von Marco13 funktioniert, danke :)

Eine Frage hätte ich noch:
Wenn ich einmal die Daten aus der Datenbank lese, stimmt die Lösung. Nur wenn ich den Select befehl ein zweites mal lese, werden die Daten einfach unten hinzugefügt. Ich möchte aber, das die Daten nicht unten hinzugefügt werden sondern die vorhanden Daten in der JTable ersetzt werden.

Wie funktioniert das?

mfg
bmwGTR
 

Michael...

Top Contributor
Wenn ich einmal die Daten aus der Datenbank lese, stimmt die Lösung. Nur wenn ich den Select befehl ein zweites mal lese, werden die Daten einfach unten hinzugefügt.
War ja auch zu erwarten, wenn man neue Daten einem Vector hinzufügt ;-)

Entweder einen neuen Vector erstellen und befüllen, den man dem TableModel übergibt, oder vor dem zweiten Select den bestehenden Vector leeren.
Letzteres hätte u.U. den Nachteil, dass falls ein Fehler auftritt eventuell gar keine oder nicht alle Daten angezeigt werden.
 
B

bmwGTR

Gast
Vielen Dank, jetzt funktioniert mein Programm so wie es sollte :)

Vielen Dank nochmals für die rasche Hilfe :)

mfg
bmwGTR
 

kniffel

Mitglied
Hallo,

ich möchte mich gleich beim Thema anschließen, da ich ein ähnliches Problem habe.
Ich habe ein Applet, dieses zeigt in mehreren JTable's, welche sich in einer JTabbedPane befinden, Daten aus einer DB an.
Ich habe 3 "Karteikarten" = Tabs.
Jänner, Februar, März.
Wenn ich zwischen den Tabs wechsle, werden die Daten von der DB gelesen und eingefügt.
Ich habe zusätzlich noch 2 Buttons. (zum lesen der daten, und zum löschen)
Wenn ich z.B. in März eine Zeile mithilfe meines Buttons lösche, wird dies auch getan und sofort automatisch auch aktualisiert.
Wechsle ich jedoch den Tab, und dann wieder auf März zurück, ist der gelöschte Eintrag wieder sichtbar.
Von der DB ist er aber gelöscht worden. (Nach einem neustart des Applets, wird der Eintrag nicht mehr angezeigt)

Ich habe über System.out.println herausgefunden, dass auch die Tabelle OHNE den Eintrag erzeugt wird. Allerdings habe ich den Verdacht, dass die alte JTable (die beim öffnen des Tabs erzeugt wurde) ÜBER der aktuellen JTable liegt.
Ich erzeuge leider jedes Mal beim abrufen eine neue JTable.
Gibt es nicht eine Lösung, wie ich die Tabelle "lösche/leere" und danach die neue aktuelle erzeuge?
Ich habe im Forum viel gesucht und gelesen, aber so wirklich habe ich keine Lösung finden können.
Ich hab viel über AbstractTableModel und die fireTableDataChanged(); bzw. fireTableStructureChanged(); gelesen, aber leider funktioniert dies auch nicht.
model.setRowCount(0); hat auch nicht weitergeholfen.
table bzw. scollPane (update(), validate(), usw.) hat auch keine wirkung.

Java:
pan4 = new JPanel();
       pan4.setLayout(null);
       pan4.setBounds(0,0,1100,1000);

          jaenner = new JPanel();
          jaenner.setLayout(null);
          jaenner.setBackground(Color.LIGHT_GRAY);
       
          februar = new JPanel();
          februar.setLayout(null);
          februar.setBackground(Color.LIGHT_GRAY);
          
          maerz = new JPanel();
          maerz.setLayout(null);
          maerz.setBackground(Color.LIGHT_GRAY);
       
          //Error wenn kein Button
          testbut = new JButton("Disabled");
          testbut.setBounds(50,50,150,50);
          testbut.setEnabled(false);
          jaenner.add(testbut);
       

          tabbedPane.addTab("Jänner", null, jaenner,"Text");
          tabbedPane.setMnemonicAt(0,KeyEvent.VK_1);
          tabbedPane.addTab("Februar", null, februar,"Text");
          tabbedPane.setMnemonicAt(1,KeyEvent.VK_1);
          tabbedPane.addTab("März", null, maerz,"Text");
          tabbedPane.setMnemonicAt(2,KeyEvent.VK_1);

          //tabbedPane.addChangeListener(this);
          tabbedPane.addChangeListener(new ChangeListener() {
              public void stateChanged(ChangeEvent ce) {
                    tabbedPane = (JTabbedPane) ce.getSource();
                    switch (tabbedPane.getSelectedIndex()) {
                           case 0:
                                tabelle="daten";
                                getdata();
                                scrollPane = new JScrollPane(table);
                                scrollPane.setBounds(1,1,450,515);
                                jaenner.add(scrollPane);
                                break;
                           case 1:
                                tabelle="februar";
                                getdata();
                                scrollPane = new JScrollPane(table);
                                scrollPane.setBounds(1,1,450,515);
                                februar.add(scrollPane);
                                break;
                           case 2:
                                tabelle="maerz";
                                //model.fireTableStructureChanged();
                                //model.fireTableDataChanged();
                                //model.setRowCount(0);
                                getdata();
                                scrollPane = new JScrollPane(table);
                                scrollPane.setBounds(1,1,450,515);
                                maerz.add(scrollPane);
                                break;
                    }//Ende switch
              }//Ende stateChanged
          });//Ende changelistener

          tabbedPane.setBounds(25,135,450,540);
       pan4.add(tabbedPane);

       //Panels zusammenführen
       pan.add(pan2);
       pan.add(pan3);
       pan.add(pan4);
       //Panel setzen
       add(pan);
}//Ende init

Hier meine daten-lesen-methode
Java:
public void getdata() {
       Vector<String> columnNames = new Vector<String>();
       Vector<Vector> data = new Vector<Vector>();
       try {
           Class.forName(driver);
           Connection connection = DriverManager.getConnection(databaseURL, DATABASE_USER, USER_PASSWORD);
           String sql = "SELECT * FROM "+tabelle+";";
           Statement stmt = connection.createStatement();
           ResultSet rs = stmt.executeQuery(sql);
           ResultSetMetaData md = rs.getMetaData();
           int columns = md.getColumnCount();
           //Get column names
           for (int i=1;i<=columns;i++) {
               columnNames.addElement(md.getColumnName(i));
               }//Ende for
           //Get row data
           while (rs.next()) {
                 Vector<Object> row = new Vector<Object>(columns);
                 for (int i=1;i<=columns;i++) {
                     row.addElement(rs.getObject(i));
                     }//Ende for
                data.addElement(row);
            }//Ende while
            rs.close();
            stmt.close();
            connection.close();

        }//Ende try
        catch (Exception e) {
              System.out.println(e);
              console.append(String.valueOf(e+"\n"));
              }//Ende catch
        //model = new DefaultTableModel(data,columnNames);

        table = new JTable(data,columnNames);

}//Ende getdata


Hier meine delete-methode

Java:
public void deletedata() {
       String nummer;
           nummer = JOptionPane.showInputDialog(null,"Welche Zeile soll gelöscht werden? \n Geben Sie die entsprechende 'nr' ein.");
           console.setText(console.getText()+nummer);
           Vector<String> columnNames = new Vector<String>();
           Vector<Vector> data = new Vector<Vector>();
           try {
               Class.forName(driver);
               Connection connection = DriverManager.getConnection(databaseURL, DATABASE_USER, USER_PASSWORD);
               Statement stmt = connection.createStatement();
               stmt.executeUpdate("DELETE FROM "+tabelle+" WHERE nr="+Integer.parseInt(nummer)+";");
               stmt.close();
               connection.close();
           }//Ende try
           catch(Exception e) {
           System.out.println(e);
           console.append(String.valueOf(e+"\n"));
           }//Ende catch
           getdata();
           switch (tabbedPane.getSelectedIndex()) {
                  case 0:
                         scrollPane = new JScrollPane(table);
                         scrollPane.setBounds(1,1,450,515);
                         jaenner.add(scrollPane);
                         console.append("Deleted from Jänner");
                         break;
                  case 1:
                         scrollPane = new JScrollPane(table);
                         scrollPane.setBounds(1,1,450,515);
                         februar.add(scrollPane);
                         console.append("Deleted from Februar");
                         break;
                  case 2:
                         scrollPane = new JScrollPane(table);
                         scrollPane.setBounds(1,1,450,515);
                         maerz.add(scrollPane);
                         console.append("Deleted from März");
                         break;
           }//Ende switch

}//Ende deletedata
 

Marco13

Top Contributor
Von der Struktur her eher häßlich. Die minimale Änderung, mit der zumindest die chance besteht, dass es funktionieren KÖNNTE, wäre sowas wie

jaenner.remove(scrollPane); // Erst die alte entfernen, dann die neue hinzufügen
scrollPane = new JScrollPane(table);
scrollPane.setBounds(1,1,450,515);
jaenner.add(scrollPane);

Kann aber auch gut sein, dass da noch mehr im Argen liegt...
 

kniffel

Mitglied
Dankeschön :)
Es funktioniert, wenn ich jaenner.removeAll(); aufrufe.

Wie könnte ich deiner Meinung nach, die Struktur verbessern?
Meinst du z.B.:
statt:
Java:
case 1:
                                tabelle="februar";
                                getdata();
                                februar.removeAll();
                                scrollPane = new JScrollPane(table);
                                scrollPane.setBounds(1,1,450,515);
                                februar.add(scrollPane);
                                break;
so: Bounds und new JScrollPane in getdata();
Java:
case 1:
                                tabelle="februar";
                                getdata();
                                februar.removeAll();
                                februar.add(scrollPane);
                                break;

Was kann ich hier tun, da das Applet noch nicht fertig ist und definitiv noch größer wird, um die Struktur zu verbessern?

Vielen vielen Dank nocheinmal :)
 

Marco13

Top Contributor
Dass da bei getdata (was getData heißen sollte, oder besser: Einen Namen, der besser klar macht, was GENAU dort passiert) die Datenbankanbindung und GUI-Code vermischt sind, ist nicht so schön.

Einerseits sollte man trennen zwischen dem Laden der Daten und dem Erzeugen der GUI-Elemente (bzw. deren Einfügen ins GUI). In diesem Fall sollten vermutlich eher die Daten geladen werden, und diese sollten dann in ein DefaultTableModel eingefügt werden (das zu der Tabelle gehört, wo sie hin sollen) - dann erspart man sich auch das Neu-Erstellen der Tabelle und so...

Andererseits muss man damit rechnen, dass die Datenbankabfrage lange dauert, und das ganze sollte mit einen SwingWorker im Hintergrund gemacht werden. Das wird dann etwas aufwändiger (nicht dramatisch, aber eben etwas...). So ist das. Programmieren ist einfach. Gut programmieren ist schwer.
 

Neue Themen


Oben