JTable wird nicht aktualisiert

soGehtDas

Grünschnabel
Hallo Community,

dies ist mein erster Post bei euch, lang und oft hab ich hier schon lesend Hilfe fuer meine kleinen Java-Probleme gefunden, doch diesmal finde ich leider keine Loesung.

Mein Problem: ich hab einen leeren JTable, welchen ich nach und nach mit Daten fuettern will, aber egal wie oft ich meinen JDialog zur Dateneingabe aufrufe, mein Table bleibt leer. Die Daten beziehe ich aus einer ArrayList, deren Infos ich in ein 2d-Array packe, welches dann in meinem JTable angezeigt werden soll, was aber nicht passiert.

Das Programm soll eine "Buchverwaltung" werden. Sinn: einarbeiten ins Swing.

Fuer die GUI
Java:
package bibliothek;

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

public class BiblGUI extends JFrame {

    Container cp = getContentPane();

    Border etche = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);

    JPanel mainPane = new JPanel(new BorderLayout());
    JPanel ceContent = new JPanel(new BorderLayout());
    JPanel noSymbol = new JPanel();
    JPanel weFunc = new JPanel(new BorderLayout());
    JPanel eaPane = new JPanel();
    JPanel soPane = new JPanel();

    JButton neuBuch = new JButton("Hinzufügen");
    JButton delBuch = new JButton("Testen");

    JTabbedPane tp = new JTabbedPane();

    public static JTable buchTable;
    private String[] spaltenNamen = { "Titel", "Autor", "Kategorie", "Bewertung" };
    private String[][] buchDatenArr;

    private final String[] NAMES = {"1", "2", "3", "3", "4", "5"};
    JList buchListe = new JList(NAMES);

    private BuchInputDialog bid;

    // ~~~~~~~~~~~~~~~~~~~~~~~~~
    // ------ Konstruktor ------

    public BiblGUI() throws Exception {
        super();
        this.setTitle("Buecher-Archiv");

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // ------ JFrame Settings ------

        Dimension frameSize = new Dimension(800, 600);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int posX = (screenSize.width - frameSize.width) / 2;
        int posY = (screenSize.height - frameSize.height) / 2;
        this.setSize(frameSize);
        this.setLocation(posX, posY);

        this.setResizable(false);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // ------ anonyme ButtonListener ------

        neuBuch.addActionListener( new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                bid = new BuchInputDialog();
            }
        });

        delBuch.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                System.out.println(Buch.buecherListe);
            }
        });

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // ------ Komponenten Settings ------

        mainPane.setBorder(etche);
        noSymbol.setBorder(etche);
        soPane.setBorder(etche);
        eaPane.setBorder(etche);

        buchDatenArr = Buch.createBuchListe();
        buchTable = new JTable(buchDatenArr, spaltenNamen);

        tp.addTab("Nummer 1", new JScrollPane(buchTable));
        tp.addTab("Nummer 2", buchListe);
        ceContent.add(tp);

        //weFunc.add(neuBuch, BorderLayout.NORTH);
        //weFunc.add(delBuch, BorderLayout.SOUTH);

        noSymbol.add(neuBuch);
        noSymbol.add(delBuch);

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // ------ Komponenten in mainPane ------

        mainPane.add(ceContent, BorderLayout.CENTER);
        mainPane.add(noSymbol, BorderLayout.NORTH);
        mainPane.add(weFunc, BorderLayout.WEST);
        mainPane.add(soPane, BorderLayout.SOUTH);
        mainPane.add(eaPane, BorderLayout.EAST);
        
        cp.add(mainPane);
    }
}

meine Buch Klasse:
Java:
package bibliothek;

import java.util.*;

class Buch {

    public static final String[] KATEGORIEN = { "Fachbuch", "Belletristik", "Sachbuch"};
    public static final String[] GENRE_FB = { "Programmierung", "Betriebssysteme", "Webtechnik", "Sonstiges"};
    public static final String[] GENRE_BT = { "Lyrik", "Fantasy", "SciFi", "Sonstiges"};
    public static final String[] GENRE_SB = { "Natur", "Wissenschaft", "Bilder"};
    public static final int[] bewertungSys  = { 1, 2, 3, 4, 5 };
    private final String erstellDatum = "";

    public static List<Buch> buecherListe = new ArrayList<Buch>();
    private static Buch[] buecherArray;
    private static int listenLaenge;
    private static String[][] buchDetArr;

    private String autor;
    private String titel;
    private String erscheinung;
    private int bewertung;
    private String kategorie;
    private String genre;

    // ------------- Konstruktoren -------------

    public Buch(String autor, String titel, String kategorie) {
        this.autor = autor;
        this.titel = titel;
        
        this.kategorie = "";
        this.bewertung = 0;
    }

    public Buch(String autor, String titel, String kategorie, String genre, int bewertung) {

        this.autor = autor;
        this.titel = titel;
        this.kategorie = kategorie;
        this.genre = genre;
        this.bewertung = bewertung;
    }

[ .... setter und getter hab ich mal weggelassen... ]

und mein eigener Dialog zum "fuettern":
Java:
package bibliothek;

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;

public class BuchInputDialog extends JDialog {

    private String titelEingabe;
    private String autorEingabe;
    private String kategorieWahl;

    private JLabel titelLabel = new JLabel("Titel*");
    private JLabel autorLabel = new JLabel("Autor*");
    private JLabel hinweisLabel = new JLabel("* Pflichtfelder");

    private JTextField titelFeld = new JTextField("Titel eingeben...");
    private JTextField autorFeld = new JTextField("Autor eingeben...");

    private JComboBox genreWahlBox = new JComboBox(Buch.KATEGORIEN);

    private JButton okButton = new JButton("OK");
    private JButton abbrechenButton = new JButton("Abbrechen");

    JPanel inhaltPanel = new JPanel();

    public BuchInputDialog() {
        super();
        setTitle("Neues Buch...");

        Dimension frameSize = new Dimension(200, 300);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int posX = (screenSize.width - frameSize.width) / 2;
        int posY = (screenSize.height - frameSize.height) / 2;
        this.setSize(frameSize);
        this.setLocation(posX, posY);

        this.setVisible(true);

        // Listener

        okButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                titelEingabe = titelFeld.getText();
                autorEingabe = autorFeld.getText();
                kategorieWahl = genreWahlBox.getSelectedItem().toString();
                Buch.createBuch(autorEingabe, titelEingabe, kategorieWahl);
                System.out.println(Buch.buecherListe);
                dispose();
            }
        });

        abbrechenButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                dispose();
            }
        });
       
        // Ende Listener

        inhaltPanel.setLayout(new BoxLayout(inhaltPanel, BoxLayout.Y_AXIS));

        inhaltPanel.add(titelLabel);
        inhaltPanel.add(titelFeld);
        inhaltPanel.add(autorLabel);
        inhaltPanel.add(autorFeld);
        inhaltPanel.add(genreWahlBox);
        inhaltPanel.add(new JLabel(""));
        inhaltPanel.add(hinweisLabel);
        inhaltPanel.add(new JLabel(""));
        inhaltPanel.add(okButton);
        inhaltPanel.add(abbrechenButton);

        this.add(inhaltPanel);
    }

}

Hoffe, dass ihr mir helfen koennt.

Gruessle,
sGD
 
Zuletzt bearbeitet:
Du hast leider die Methode Buch.createBuch nicht gepostet. Die wäre glaube ich noch ganz interessant.

Versuche mal die ganzen static (außer bei Konstanten) wegzulassen und stattdessen die Objekte aneinander zu übergeben um Instanzvariablen verwenden zu können. static ist sehr gefährlich wenn man es so benutzt.

Denke auch dran immer die minimale Sichtbarkeit für Variablen zu verwenden. Also private auch für alle Swing Teile. Ich würde es übrigens vermeiden für GUI-Elemente die du nie wieder brauchst Felder anzulegen. Das macht es später recht unübersichtlich damit zu programmieren.
 
Sry, die hab ich vergessen, sind noch ein paar andere. dabei

Java:
// ------------- buchverwaltende Methoden -------------

    public static void createBuch(String autor, String titel, String kategorie) {
        Buch neuBuch = new Buch(autor, titel, kategorie);
        buecherListe.add(neuBuch);
    }

    public static String[][] createBuchListe(){
        buchDetArr = new String[buecherListe.size()][4];
        int listSize = buecherListe.size();
        for(int i = 0; i < listSize; i++) {
            buchDetArr[i][0] = buecherListe.get(i).getTitel();
        }
        for(int i = 0; i < listSize; i++ ) {
            buchDetArr[i][1] = buecherListe.get(i).getAutor();
        }
        for(int i = 0; i < listSize; i++ ) {
            buchDetArr[i][1] = buecherListe.get(i).getKategorie();
        }

        return buchDetArr;
    }
}


Wie soll ich denn das dann mit der arraylist machen, in der ich die Buecher speichern, ohne dass sie statisch ist?

bei den anderen sachen koennt ich mir das ja zum Teil noch vorstellen...
werds mir nochmal anschaun.
 
Die Bücherliste im Buch zu haben macht ja eh nicht so viel Sinn. Du solltest dir noch ein neues Objekt Bücherei oder so zulegen in dem du eine Bücherliste hast. Darauf machst du eine Methode addBuch(Buch) und die fügt das Buch in die Liste hinzu.

Was bei dir wohl am Besten wäre, ist ein eigenes Tabellenmodell. Swing verwendet das MVC-Pattern. Hast du dir das mal angeschaut? Wenn sich etwas am Modell (also deiner Bücherliste) ändert, wird die View (deine Tabelle) benachrichtigt, dass sie sich aktualisieren muss.
 
So, hab jetzt eine neue Klasse Archiv erstellt, in der die BuchListe steckt, dort hab ich dann auch die Methode reingepackt, um mein Array fuer mein Table zu fuellen.

Static ist jetzt nichts mehr ausser die Konstanten.

Mein Problem ist jetzt aber: wo muss ich eine Instanz von Archiv erstellen, damit ich aus den anderen Klassen draus zugreifen kann?! Hoffe, dass ihr versteht....

Klasse Archiv:
Java:
package bibliothek;

import java.util.*;

class Archiv {

    public List<Buch> buecherListe = new ArrayList<Buch>();
    private String[][] buchDetailArr;

    public void addBuch(Buch neuBuch) {
        buecherListe.add(neuBuch);
    }

    public String[][] createBuchListe(){
        buchDetailArr = new String[buecherListe.size()][4];
        int listSize = buecherListe.size();
        for(int i = 0; i < listSize; i++) {
            buchDetailArr[i][0] = buecherListe.get(i).getTitel();
        }
        for(int i = 0; i < listSize; i++ ) {
            buchDetailArr[i][1] = buecherListe.get(i).getAutor();
        }
        for(int i = 0; i < listSize; i++ ) {
            buchDetailArr[i][1] = buecherListe.get(i).getKategorie();
        }

        return buchDetailArr;
    }
}

achja, mein JFrame wird in ner extra Klasse mit main-Funktion erstellt, in dieser Klasse passiert sonst nix anderes ausser ein "BiblGUI bg = new BiblGUI();"
 
In deiner GUI-Klasse erstellst du eine Instanz von deinem Archiv. Diese Instanz kannst du dann bei Bedarf weitergeben.

Dein Dialog erstellt dann ein Buch und gibt dieses zurück (indem du eine Methode getBuch() anbietest du du aufrufst nachdem der Dialog zu ist).

Das neue Buch kannst du dann in dein Archiv einfügen.

Das mit der Array-Erstellung für die Tabelle kannst du dir sparen wenn du ein eigenes Tabellenmodell verwendest. Dieses kann dann direkt auf deinem Archiv arbeiten.

Probier mal die Beispiele hier aus: http://openbook.galileocomputing.de...16_018.htm#mj97a8a66019c55b6d81e709445d33b8fe
 
So, danke zeja.

Hab mein Problem nun mit deinen Vorschlaegen geloest. mein TableModel sieht folgendermassen aus:

Java:
package bibliothek;

import java.util.List;
import javax.swing.table.*;

class BuchTabellenModell extends AbstractTableModel {

    private List<Buch> arLi;
    private String stringRueck;
    private String[] spaltenNamen = { "Titel", "Autor", "Kategorie", "Bewertung" };

    public BuchTabellenModell(List<Buch> arLi) {
        this.arLi = arLi;
    }

    @Override public int getColumnCount() {
        return 4;
    }

    @Override public String getColumnName(int column) {
        return this.spaltenNamen[column];
    }

    @Override public int getRowCount() {
        return arLi.size();
    }

    @Override public Object getValueAt(int row, int column) {
        if(column == 3) {
                this.stringRueck = arLi.get(row).getBewertung();     
        } else if(column == 2) {
                this.stringRueck = arLi.get(row).getKategorie();
        } else if(column == 1) {
                 this.stringRueck = arLi.get(row).getAutor();
        } else if(column == 0) {
                this.stringRueck = arLi.get(row).getTitel();
        }
        return this.stringRueck;
    }

}

Die Aktualisierung hab ich in meiner GUI-Klasse ueber n Timer realisiert. tm ist eine Instanz meines TableModels:

Java:
    private Timer tabellenUpdater = new Timer(1000, new ActionListener(){
        public void actionPerformed(ActionEvent e) {
            tm.fireTableDataChanged();
        }
    });

Danke nochmal fuer die vielen Tips die ueber mein Problem hinausgingen.

Jetzt werd ich mich mal an die Serialisierung machen. Mal schaun, ob ich das hinbekomme.

Gruessle,
sGD
 
Hallo zusammen,

Stueck fuer Stueck komm ich weiter, aber nun bin ich irritiert. Mein GUI ist an sich okay, nur wird es nicht bei jedem Start komplett angezeigt, mnachmal erscheint naemlich nur die Menuleiste von meinem Frame, aber die ganzen Panels fehlen. Das passiert sowohl bei der Ausfuehrung in der IDE (NetBeans 6.7) als auch beim Ausfuehren der jar-Datei.

Ausserdem hab ich ein Problem mit der Deserialisierung, weiss naemlich nicht, warum er nichts einliesst, bzw das, was er einliesst nicht anzeigt.


Da mal meine Menueleiste:
Java:
package bibliothek;

import java.io.*;
import javax.swing.*;
import java.awt.event.*;

class BiblioMenuBar extends JMenuBar {

    private JMenu fileMenu;
    private JMenu editMenu;

    private JMenuItem fNeuBuchItem;
    private JMenuItem fLadenItem;
    private JMenuItem fSpeichernItem;
    private JMenuItem fBeendenItem;


    private BuchInputDialog bid;
    private Archiv archiv;
    private BuchTabellenModell btm;

    public BiblioMenuBar(final Archiv archiv, final BuchTabellenModell btm) {
        super();

        this.archiv = archiv;

        // ~~~~~~~~~~~~~~~~~~~~~~~~
        // ------ Datei-Menu ------
        fileMenu = new JMenu("Datei");
        fileMenu.setMnemonic('D');

        fNeuBuchItem = new JMenuItem("Neues Buch", 'N');
        fNeuBuchItem.addActionListener( new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                bid = new BuchInputDialog(archiv);
            }
        });

        Action ladenAction = new AbstractAction("Laden") {
            public void actionPerformed(ActionEvent e) {
                try {
                    ObjectInputStream is = new ObjectInputStream(new FileInputStream("archiv1.ser"));
                    BiblioMenuBar.this.archiv = (Archiv)is.readObject();
                } catch(IOException ex) {
                    System.err.print(ex);
                } catch(ClassNotFoundException ex) {
                    System.err.print(ex);
                }
            }};

        Action speicherAction = new AbstractAction("Speichern") {
            public void actionPerformed(ActionEvent e) {
                try {
                    ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("archiv1.ser"));
                    os.writeObject(archiv);
                    os.close();
                } catch(IOException ex) {
                    System.err.println(ex.toString());
                }
            }
        };

        Action exitAction = new AbstractAction( "Beenden" ) {
            public void actionPerformed( ActionEvent e ) {
                System.exit( 0 );
        }};

        fileMenu.add(fNeuBuchItem);
        fileMenu.addSeparator();
        fileMenu.add(speicherAction);
        fileMenu.add(ladenAction);
        fileMenu.addSeparator();
        fileMenu.add(exitAction);

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // ------ Bearbeiten-Menu ------
        editMenu = new JMenu("Bearbeiten");

        this.add(fileMenu);
        this.add(editMenu);


    }

}

und falls es wichtig ist, meine aktuelle BiblGUI.java
Java:
package bibliothek;

import java.awt.event.*;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.Timer;
//import javax.swing.table.TableRowSorter;

class BiblGUI extends JFrame {

    private Container cp = getContentPane();

    Border etche = BorderFactory.createEtchedBorder(EtchedBorder.LOWERED);

    private Archiv arc = new Archiv();
    private BuchTabellenModell tm;

    private BiblioMenuBar bmb = new BiblioMenuBar(arc, tm);

    private JPanel hauptPanel = new JPanel(new BorderLayout());
    private JPanel centerPanel = new JPanel(new BorderLayout());
    private JPanel nordPanel = new JPanel();
    private JPanel westPanel = new JPanel(new BorderLayout());
    private JPanel ostPanel = new JPanel();
    private JSplitPane splitter;

    private JButton neuBuch = new JButton("Hinzufügen");
    private JButton delBuch = new JButton("Löschen");
    private JTextField suchInput = new JTextField("Noch ohne Funktion", 25);
    private JButton suchenButton = new JButton("Los");

    private JTabbedPane tp = new JTabbedPane();

    private JTable buchTable;

    private final String[] NAMES = {"1", "2", "3", "3", "4", "5"};

    private BuchInputDialog bid;
    
    private Timer tabellenUpdater = new Timer(2500, new ActionListener(){
        public void actionPerformed(ActionEvent e) {
            tm.fireTableDataChanged();
        }
    });

    // ~~~~~~~~~~~~~~~~~~~~~~~~~
    // ------ Konstruktor ------

    public BiblGUI() throws Exception {
        super();
        this.setTitle("Buecher-Archiv");

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // ------ JFrame Settings ------

        Dimension frameSize = new Dimension(800, 550);
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        int posX = (screenSize.width - frameSize.width) / 2;
        int posY = (screenSize.height - frameSize.height) / 2;
        this.setSize(frameSize);
        this.setLocation(posX, posY);

        this.setResizable(false);
        this.setVisible(true);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.setJMenuBar(bmb);

        tabellenUpdater.start();

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // ------ anonyme ButtonListener ------

        neuBuch.addActionListener( new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                try {
                    bid = new BuchInputDialog(arc);
                } catch(Exception ex) {
                    System.err.print(ex);
                }finally {
                    tm.fireTableDataChanged();
                }
            }
        });

        delBuch.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                int iDelete = buchTable.getSelectedRow();
                if(iDelete != -1)
                    arc.buecherListe.remove(iDelete);
                else
                    return;
            }
        });

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // ------ Komponenten Settings ------

        tm = new BuchTabellenModell(arc.buecherListe);
        buchTable = new JTable(tm);
        buchTable.setRowSelectionAllowed(true);
        buchTable.setCellSelectionEnabled(true);

        tp.addTab("  Bücher  ", new JScrollPane(buchTable));
        tp.addTab("  Liste   ", new JList(NAMES));

        splitter = new JSplitPane(JSplitPane.VERTICAL_SPLIT, true, tp, centerPanel);

        centerPanel.setBorder(etche);
        ostPanel.setBorder(etche);
        westPanel.setBorder(etche);

        nordPanel.add(neuBuch);
        nordPanel.add(delBuch);
        nordPanel.add(new JLabel("                             |"));
        nordPanel.add(new JLabel("Suche:"));
        nordPanel.add(suchInput);
        nordPanel.add(suchenButton);

        // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        // ------ Komponenten in hauptPanel ------

        hauptPanel.add(splitter, BorderLayout.CENTER);
        hauptPanel.add(nordPanel, BorderLayout.NORTH);
        hauptPanel.add(westPanel, BorderLayout.WEST);
        hauptPanel.add(ostPanel, BorderLayout.EAST);

        cp.add(hauptPanel);
    }
}

Info: die Klasse Archiv enthaelt eine ArrayList mit Objekten vom Typ Buch (Klassen siehe oben). Beide Klassen implementieren die das Serializable-Interface.

Weiss echt nicht, woran es liegen kann (vor allem mein GUI-Problem ist mir ein Raetsel) und google hat mir auch nicht helfen koennen.

Gruessle,
sGD
 
Also ersteres: Du machst schon ein setVisible(true) bevor du deine GUI fertig aufgebaut hast. Das gehört immer ganz ans Ende. Das Fenster zentrieren geht übrigens auch mit setLocationRelativeTo(null).

Serialisieren ist meist keine so gute Idee. Ich würde dir empfehlen das nach XML zu speicher. Das geht mir XStream mit genau so wenig Handgriffen. Man kann es sich ordentlich anschauen und auch dann wieder einlesen wenn sich die Klassen nach der Serialisierung geändert haben.
 
Okay, dann werd ich deine Hinweise mal umsetzen, das mit dem setVisible haette mir auch selber auffallen koennen :D

Ich meine in der Insel gelesen zu haben, dass man fuer XML JavaBeans braucht, damit hab ich aber bisher nichts gemacht, werd mir das aber trotzdem mal anschaun. XML waere mir naemlich auch lieber gewesen (Ist glaub ich auch vom Lernfaktor effektiver).

Danke auf jeden Fall. Meld mich, wenn ichs umgesetzt hab.

Edit: so, die GUI-Probleme sind geloest, danke dir. Werd mich jetzt noch um die XML-Geschichte kuemmern.
 
Zuletzt bearbeitet:
Zurück