Swing Mal wieder JTable Ansicht aktualisieren

Diskutiere Mal wieder JTable Ansicht aktualisieren im AWT, Swing, JavaFX & SWT Forum; Moin, ich hänge gerade gedanklich fest und verstehe etwas nicht. Zum Programm: - JFrame mit drei JPanels: Button-Panel, Steuerungspanel,...

  1. Snape
    Snape Mitglied
    Moin,
    ich hänge gerade gedanklich fest und verstehe etwas nicht.
    Zum Programm:
    - JFrame mit drei JPanels: Button-Panel, Steuerungspanel, Positionspanel (mit JTable)
    - Die Tabelle hat ein eigenes TableModel von mir verpasst bekommen und bekomt initial einen Dummy-Eintrag, der auch angezeigt wird.
    - Jede Tabellenzeile wird durch ein eigenes Objekt dargestellt.
    - Die Tabellenzeilen werden als List im TableModel verwaltet.
    - Im Steuerungspanel möchte ich per Buttonklick Tabellenzeilen hinzufügen oder löschen.
    - Das Hinzufügen per Button funktioniert im TableModel (Leereintrag der Liste hinzufügen), aber trotz Aufruf von fireTableDataChanged() im TableModel nach Hinzufügen des neuen Eintrags wird die Tabelle in der GUI nicht aktualisiert.
    - Die Debugausgaben zeigen mir, dass die zusätzlichen Zeilen in der Liste / TableModel korrekt hinzugefügt wurden.
    -> Die Anzeige in der GUI aktualisiert sich erst dann, wenn ich per Doppelklick in die eine (initiale) Tabellenzelle diese editiere. Plötzlich werden die hinzugefügten Zeilen angezeigt.

    Wo ist mein Denkfehler, warum wird die GUI nicht sofort aktualisiert?
     
  2. Vielleicht hilft dir dieser Kurs hier weiter.
  3. Harry Kane
    Harry Kane Bekanntes Mitglied
    Ohne Code zu sehen, wird das ganze zum Blick in die Glaskugel.
    Ist dein eigenes TableModel von DefaultTableModel oder AbstractTableModel abgeleitet?
     
  4. Snape
    Snape Mitglied
    Vom DefaultTableModel.

    OK, dann hier mein Code:
    Code (Java):
    import javax.swing.JOptionPane;
    import javax.swing.event.TableModelEvent;
    import javax.swing.event.TableModelListener;

    public class EditableTableForm extends javax.swing.JFrame implements TableModelListener {

        /**
         * Creates new form EditableTableForm
         */

        public EditableTableForm() {
            initComponents();
            initComponents2();
        }

        /**
         * 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() {
            java.awt.GridBagConstraints gridBagConstraints;

            jpList = new javax.swing.JPanel();
            jscrListe = new javax.swing.JScrollPane();
            jtList = new javax.swing.JTable();
            jpListControls = new javax.swing.JPanel();
            jbAddEntry = new javax.swing.JButton();
            jbDeleteEntry = new javax.swing.JButton();
            jpButtons = new javax.swing.JPanel();
            jbClose = new javax.swing.JButton();

            setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
            setMinimumSize(new java.awt.Dimension(400, 800));
            setName("Einkaufsliste"); // NOI18N
            getContentPane().setLayout(new java.awt.GridBagLayout());

            jpList.setMinimumSize(new java.awt.Dimension(350, 750));
            jpList.setPreferredSize(new java.awt.Dimension(350, 750));
            jpList.setLayout(new java.awt.BorderLayout());

            jscrListe.setViewportView(jtList);

            jpList.add(jscrListe, java.awt.BorderLayout.CENTER);

            gridBagConstraints = new java.awt.GridBagConstraints();
            gridBagConstraints.gridx = 0;
            gridBagConstraints.gridy = 0;
            gridBagConstraints.weighty = 1.0;
            getContentPane().add(jpList, gridBagConstraints);

            jpListControls.setMinimumSize(new java.awt.Dimension(50, 100));
            jpListControls.setPreferredSize(new java.awt.Dimension(50, 100));
            jpListControls.setLayout(new java.awt.GridLayout(2, 0));

            jbAddEntry.setLabel("+");
            jbAddEntry.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    jbAddEntryActionPerformed(evt);
                }
            });
            jpListControls.add(jbAddEntry);

            jbDeleteEntry.setText("-");
            jbDeleteEntry.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    jbDeleteEntryActionPerformed(evt);
                }
            });
            jpListControls.add(jbDeleteEntry);

            gridBagConstraints = new java.awt.GridBagConstraints();
            gridBagConstraints.gridx = 1;
            gridBagConstraints.gridy = 0;
            gridBagConstraints.anchor = java.awt.GridBagConstraints.NORTHEAST;
            getContentPane().add(jpListControls, gridBagConstraints);

            jpButtons.setLayout(new java.awt.BorderLayout());

            jbClose.setText("Schliessen");
            jbClose.addActionListener(new java.awt.event.ActionListener() {
                public void actionPerformed(java.awt.event.ActionEvent evt) {
                    jbCloseActionPerformed(evt);
                }
            });
            jpButtons.add(jbClose, java.awt.BorderLayout.EAST);

            gridBagConstraints = new java.awt.GridBagConstraints();
            gridBagConstraints.gridx = 0;
            gridBagConstraints.gridy = 1;
            gridBagConstraints.gridwidth = 2;
            gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL;
            gridBagConstraints.anchor = java.awt.GridBagConstraints.SOUTH;
            gridBagConstraints.weightx = 1.0;
            getContentPane().add(jpButtons, gridBagConstraints);

            pack();
        }// </editor-fold>                      

        private void jbCloseActionPerformed(java.awt.event.ActionEvent evt) {                                      
            int iReturn = JOptionPane.showConfirmDialog(this, "Programm wirklich beenden?", "Bestätigung", JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE);
            // 0 = OK; 1 = CANCEL
            switch (iReturn) {
                case JOptionPane.OK_OPTION:
                    System.exit( 0 );
            }
        }                                      

        private void jbAddEntryActionPerformed(java.awt.event.ActionEvent evt) {                                          
            ((EditableTableModel)jtList.getModel()).addEmptyEntry();
            jtList.validate();
            jtList.repaint();
        }                                        

        private void jbDeleteEntryActionPerformed(java.awt.event.ActionEvent evt) {                                            
            // TODO add your handling code here:
        }                                            

        /**
         * @param args the command line arguments
         */

        public static void main(String args[]) {
            /* Set the Nimbus look and feel */
            //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
            /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
             * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
             */

            try {
                for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                    if ("Nimbus".equals(info.getName())) {
                        javax.swing.UIManager.setLookAndFeel(info.getClassName());
                        break;
                    }
                }
            } catch (ClassNotFoundException ex) {
                java.util.logging.Logger.getLogger(EditableTableForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (InstantiationException ex) {
                java.util.logging.Logger.getLogger(EditableTableForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (IllegalAccessException ex) {
                java.util.logging.Logger.getLogger(EditableTableForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            } catch (javax.swing.UnsupportedLookAndFeelException ex) {
                java.util.logging.Logger.getLogger(EditableTableForm.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
            }
            //</editor-fold>
            //</editor-fold>

            /* Create and display the form */
            java.awt.EventQueue.invokeLater(new Runnable() {
                public void run() {
                    new EditableTableForm().setVisible(true);
                }
            });
        }

        // Variables declaration - do not modify                    
        private javax.swing.JButton jbAddEntry;
        private javax.swing.JButton jbClose;
        private javax.swing.JButton jbDeleteEntry;
        private javax.swing.JPanel jpButtons;
        private javax.swing.JPanel jpList;
        private javax.swing.JPanel jpListControls;
        private javax.swing.JScrollPane jscrListe;
        private javax.swing.JTable jtList;
        // End of variables declaration                  

        private void initComponents2() {
            jtList.setModel(new EditableTableModel());
        }

        @Override
        public void tableChanged(TableModelEvent tme) {
            System.out.println("tableChanged aufgerufen");
        }
    }
     
    Code (Java):
    import java.util.ArrayList;
    import java.util.List;
    import javax.swing.event.TableModelListener;
    import javax.swing.table.DefaultTableModel;

    /**
    * Klasse fuer das Datenmodell der Liste
      */

    public class EditableTableModel extends DefaultTableModel {

        private TableModelListener listener;
        private List<TableRow> entries;
        private final Class[] columnClasses = {String.class, Integer.class};
        private final String[] columnNames = {"Name", "Anzahl"};
       
        public EditableTableModel() {
            addEntry(new TableRow("Schuhe", 5, getEntries().size()));
        }

        @Override
        public int getRowCount() {
            System.out.println("Anzahl Zeilen: " + getEntries().size());
            return ( getEntries().size() );
        }

        @Override
        public int getColumnCount() {
            return columnClasses.length;
        }

        @Override
        public String getColumnName(int i) {
            return columnNames[ i ];
        }

        @Override
        public Class<?> getColumnClass(int i) {
            return columnClasses[ i ];
        }

        @Override
        public boolean isCellEditable(int i, int i1) {
            return true;
        }

        @Override
        public Object getValueAt(int row, int column) {
            Object value;
           
            switch ( column ){
                case 0: // Artikel
                    value = ((TableRow)getEntries().get(row)).getPositionsName();
                    break;
                case 1: // Anzahl
                    value = ((TableRow)getEntries().get(row)).getAmount();
                    break;
                default:
                    value = null;
                    break;
            }
            System.out.println("Value at row " + row + "; column " + column + ": " + value);
            return value;
        }

        @Override
        public void setValueAt(Object theValue, int row, int column) {
            TableRow relevantRow = (TableRow) getEntries().get(row);
            System.out.println("setValueAt() mit value " + theValue.toString() + "; row " + row + "; column " + column);
            switch (column){
                case 0: // Artkelname
                    relevantRow.setPositionsName((String) theValue);
                    break;
                case 1: // Menge
                    relevantRow.setAmount((Integer) theValue);
                    break;
            }
        }

        @Override
        public void addTableModelListener(TableModelListener tableModelListener) {
            listener = tableModelListener;
        }


        public List getEntries() {
            if ( entries == null )
                entries = new ArrayList<>();
            return entries;
        }

        public void setEntries(List entries) {
            this.entries = entries;
        }

        public void addEntry(TableRow newEntry){
            getEntries().add(newEntry);
            fireTableDataChanged();
        }
       
        public void addEmptyEntry(){
            getEntries().add(new TableRow());
            System.out.println("Anzahl Einträge neu: " + getEntries().size());
            fireTableDataChanged();
        }
       
    }
     
    Code (Java):
    /**
    * Repräsentiert die einzelne Tabellenzeile
    */

    public class TableRow {

        private String positionsName;
        private Integer amount;
        private Integer index;

        public TableRow(String artikel, int theAmount) {
            if ( artikel != null)
                positionsName = artikel;
            amount = theAmount;
        }
       
        public TableRow(String theName, int theAmount, int theIndex) {
            if ( theName != null)
                positionsName = theName;
            amount = theAmount;
            index = theIndex;
        }

        public TableRow() {
            positionsName = "";
            amount = 0;
            index = 0;
        }

        public String getPositionsName() {
            return positionsName;
        }

        public void setPositionsName(String positionsName) {
            this.positionsName = positionsName;
        }

        public Integer getAmount() {
            return amount;
        }

        public void setAmount(Integer amount) {
            this.amount = amount;
        }

        public Integer getIndex() {
            return index;
        }

        public void setIndex(Integer index) {
            this.index = index;
        }

    }
     
     
  5. Harry Kane
    Harry Kane Bekanntes Mitglied
    Hm. Sieht ok aus.
    Moment. Deine überschriebene addTableModelListener-Methode sieht verdächtig aus. So wie du sie implementiert hast, gibt es immer nur einen TableModelListener, nämlich den, den du als letztes hinzugefügt hast. Eine JTable registriert sich als TableModelListener beim TableModel, und wenn später ein weiterer Listener beim TableModel registriert wird, wird die JTable als Listener deregistriert und nicht mehr über Änderungen am Model informiert.
    Schmeiss die addTableModelListener-Methode mal aus deinem TableModel raus.
     
  6. Snape
    Snape Mitglied
    Argh! Jetzt funktioniert es - so einfach. :eek: Danke!
    Wobei ich mich dennoch frage: Wo bzw. wie registriert sich denn die JTable beim TableModel? Ich weise die JTable dem Model ja gar nicht explizit zu und die Methode war eigentlich eine Code-Leiche von einem fehlgeschlagenen Versuch, die JTable dem TableModel explizit zuzuweisen.
     
  7. Harry Kane
    Harry Kane Bekanntes Mitglied
    JTable hat einen Konstruktor mit einem TableModel-Parameter, und ausserdem die Methode setModel, mit der man das Model einer bereits fertig konstruierten JTable setzen kann. In beiden Fällen registriert sich die JTable selbst beim TableModel als Listener.
    Meine Ausführungen oben gingen zwar in die richtige Richtung, waren aber nur halb richtig. Richtig ist: die fireXXX-Methoden und die addTableModelListener-Methode sind in der AbstractTableModel-Klasse definiert. Diese Klasse hat auch eine interne Liste, in der die TableModelListener abgelegt werden. Bei Aufruf der fireXXX-Methoden wird über alle Einträge in der internen TableModelListener-Liste iteriert, und deren tableChanged-Methode aufgerufen. Wenn du die addTableModelListener-Methode überschreibst, wird die interne TableModelListener-Liste nie gefüllt, und Änderungen am TableModel werden nicht weitergegeben.
     
  8. Snape
    Snape Mitglied
    Ah ok. Das heißt, wenn ich die addTableModelListener-Methode überschreibe, sollte ich darin die von mir gewünschten Listener bedienen, so dass sie entsprechend individuell reagieren können, wenn z.B. ein fireTableDataChanged-Event aufgerufen wird. Also in der Form

    myTableModel.addTableModelListener(this);

    Im TableModel dann
    Code (Java):
    public void addTableModelListener(TableModelListener tableModelListener) {
            listenerList.add(tableModelListener);
        }

        public void fireTableDataChanged(){
            for (int i = 0; i < listenerList.size(); i++) {
                TableModelListener tableModelListener = listenerList.get(i);
                tableModelListener.handleFireTableDataChanged();
            }
        }
     
    Und in der Form-Klasse entsprechend eine Implementierung der handleFireTableDataChanged()-Methode.
    Ich frage mich gerade: Macht man sowas und wenn ja wozu?
     
  9. Harry Kane
    Harry Kane Bekanntes Mitglied
    Nur, wenn man ein Observer pattern selber programmieren will.
    In deinem Fall kannst du dir die Übung aber sparen, weil Swing schon alles mitbringt:
    - Ein Observer bzw. Listener interface
    - Ein Observable (in deinem Fall AbstractTableModel), was bereits einen Mechanismus zum registrieren und zum benachrichtigen von Observern bereitstellt.
    Du musst dich lediglich um die korrekte IMplementierung der Observer/Listener-interfaces kümmern.
     
  10. Snape
    Snape Mitglied
    Was schwebt Dir da vor?
     
  11. Harry Kane
    Harry Kane Bekanntes Mitglied
    Ich verstehe die Frage nicht. Welche Objekte möchtest du denn über Änderungen am TableModel benachrichtigen, und was für Aktionen sollen die Objekte bei Änderung des TableModels auslösen? Hast du noch ein konkretes Problem?
     
  12. Wenn du Java lernen möchtest, empfehlen wir dir diesen Kurs hier
Passende Stellenanzeigen aus deiner Region:





Die Seite wird geladen...

Mal wieder JTable Ansicht aktualisieren - Ähnliche Themen

Daten in JTable wiedergeben per TableModel und MVC Pattern
Daten in JTable wiedergeben per TableModel und MVC Pattern im Forum AWT, Swing, JavaFX & SWT
jTable wiederkennen (uniqeID oder Key)
jTable wiederkennen (uniqeID oder Key) im Forum AWT, Swing, JavaFX & SWT
JTable zeigt die alte Daten wieder
JTable zeigt die alte Daten wieder im Forum AWT, Swing, JavaFX & SWT
Schon wieder JTable
Schon wieder JTable im Forum AWT, Swing, JavaFX & SWT
Mal wieder JTable
Mal wieder JTable im Forum Java Basics - Anfänger-Themen
Thema: Mal wieder JTable Ansicht aktualisieren