Du verwendest einen veralteten Browser. Es ist möglich, dass diese oder andere Websites nicht korrekt angezeigt werden. Du solltest ein Upgrade durchführen oder ein alternativer Browser verwenden.
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.
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.
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);
}
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.
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.
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.
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
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...
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.