Swing Daten in JTable wiedergeben per TableModel und MVC Pattern

CrookedPanda

Mitglied
Hallo. Ich bin gerade am Problem, dass ich zum ersten mal mit JTables arbeite und nicht genau weiß wie ich meien Daten in die Table bekomme.

Soweit habe ich eine Anwendung erstellt nach dem MVC Pattern und DAO Pattern, damit ich Daten, welche ich wiedergeben will, aus der Datenbank abfragen kann.

Das Problem nun: Ich habe ein AbstractTableModel erstellt welches das DefaultTableModel extended.

Code:
public class AbstractTableModel extends DefaultTableModel{

    /**
     *
     */
    private static final long serialVersionUID = -7354466553311529134L;
   
    private static Logger logger = Logger.getLogger(AbstractTableModel.class);
   
    private static String col[] = { "Tabelle", "UpdateCols", "AlterAuth",
            "DeleteAuth", "IndexAuth", "InsertAuth", "SelectAuth", "UpdateAuth" };
   
    private static DefaultTableModel tableModel = new DefaultTableModel(null, col);
    private static JTable table = new JTable(tableModel);

    public static JTable updateTable(DatenbankDaoImpl db) throws SQLException, IOException {
       
        table.getModel().addTableModelListener(new TableModelListener() {
           
            public void tableChanged(TableModelEvent e) {
                logger.debug(e);
            }
        });

        while (table.getRowCount() > 0) {
            ((DefaultTableModel) table.getModel()).removeRow(0);
        }
       
        for (DatenbankBean db1 : db.getDatenbank()) {
            String tabelle = db1.getTabelle();
            String updatecols = db1.getUpdatecols();
            String alterauth = db1.getAlterauth();
            String deleteauth = db1.getDeleteauth();
            String indexauth = db1.getIndexauth();
            String insertauth = db1.getInsertauth();
            String selectauth = db1.getSelectauth();
            String updateauth = db1.getUpdateauth();

            Object[] data = {tabelle, updatecols, alterauth, deleteauth, indexauth, insertauth, selectauth, updateauth};
            tableModel.addRow(data);
            logger.debug("AbstractTableModel: " + data.toString());
        }
//        table.repaint();
        return table;
    }
   
}

Dazu habe ich auch schon einen TableModelListener (Interface) erstellt.
Code:
import java.util.EventListener;

import javax.swing.event.TableModelEvent;

public interface TableModelListener extends EventListener{

    public void tableChanged(TableModelEvent e);
   
}

Allerdings kann ich 1. nicht meinen selbst erstellten TableModelListener beim Aufruf der Methode "addtableModelListener" im AbstractTableModel als Parameter übergeben, sondern nur den default TableModelListener. Versuche ich mein Interface zu übergeben, bekomme ich folgende Meldung: "The method addTableModelListener(TableModelListener) in the type TableModel is not applicable for the arguments (new TableModelListener(){})"

2. Meine AbstractTableModel Klasse wird so wie sie ist aufgerufen und meine Daten werden Zeile nach Zeile in der for-Schleife hinzugefügt. Allerdings wird die View nicht upgedated.
Code:
public class MainWindowView extends JFrame {


    private JTable table = new JTable(new AbstractTableModel());
   
    //Konstruktor
    public MainWindowView(MainWindowModel model) {
        super();
        JPanel content = new JPanel();
        content.setLayout(new FlowLayout());
       
        this.setContentPane(content);
        this.add(new JScrollPane(table));
        table.getModel().addTableModelListener(table);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }

Könnte mir jemand sagen was ich hier genau falsch mache? Leider finde ich nicht viel zum Verwenden von TableModels und TableModelListeners, die dem MVC Pattern folgen.
 

Thallius

Top Contributor
Also zunächst mal:

Der Name AbstractTableModel ist ziemlich schlecht gewählt genau wie der name table für die Tabelle. Nimm doch bitte sprechende Bezeichner wie zum Beispiel DatabaseTable und dann entsprechend natürlich DatabaseTableModel damit man weiß was zusammen gehört.

das Du einen Eventlistener nicht einem TableModelListener hinzufügen kannst erscheint doch eigentlich recht logisch?

Versuch nach dem Hinzufügen der Rows mal ein fireTableDataChanged() (oder so ähnlich) aufzurufen

Gruß

Claus
 

CrookedPanda

Mitglied
Danke für die Hilfe soweit schon mal. Habe die Variablen- und Klassenbezeichnung mal eindeutiger gemacht, sollte ja aber nichts am Problem ändern. Selbst wenn ich nun "fireTableDataChanged()" auf mein tableModel aufrufe, bekomme ich noch immer keine Ausgabe.
 
Zuletzt bearbeitet:

Harry Kane

Top Contributor
Dein AbstractTableModel ist ein DefaultTableModel und hat eine statische Variable vom Type DefaultTableModel. So ein Konstrukt kann nur schiefgehen.
Wenn du eine Instanz von deinem AbstractTableModel benutzt, bleibt die damit gebaute JTable leer, weil du das Model nie mit Daten befüllst.
Zeig mal den Code, wo du dein AbstractTableModel benutzt,
 

Harry Kane

Top Contributor
Hab gerade deine Spoilers gelesen. Wie vermutet, verwendest du eine Instanz deines AbstractTableModels. Dieses wird aber nie mit Daten befüllt, sondern nur die statischen Objekte in deiner AbstractTableModel-Klasse.
Der Fehler mit deinem TableModelListener kommt daher, weil es ein solches interface javax.swing.event.TableModelListener schon gibt. Wenn du ein weiteres interface mit demselben Namen und derselben Methodensignatur erstellst, kann es trotzdem nicht als Ersatz für das Originalinterface verwendet werden (mal ganz abgesehen von der Frage, was zwei gleichnamige interfaces mit identischen Methoden in verschiedenen packages sollten. So was waere höchstens beim Umbau eine größeren Projekts statthaft, und auch nur dann, wenn das alte interface als deprecated markiert wird.
 

CrookedPanda

Mitglied
Ich habe bisher nur versucht anhand verschiedensters ähnlicher Fragen/Probleme online und jeglichen Informationen zu JTables mir selber etwas zusammenzubauen.

Wie soll ich denn mein TableModel dann befüllen und der View bescheid geben, dass es befüllt wurde? Habe jetzt schon mal meinen eigenen TableListener rausgeworfen. Ich habe keine Ahnung warum das online so vorgeschlagen wurde, wenn schon einer mit derselben Funktion existiert.

Um es nochmal klarzustellen, die Methode updateTable() in meinem TableModel wird so aufgerufen und die Daten werden auch über addRow() jedesmal hinzugefügt. Also wieso sollte die Tabelle nicht befüllt werden?
 
Zuletzt bearbeitet:

Harry Kane

Top Contributor
Ich habe keine Ahnung warum das online so vorgeschlagen wurde, wenn schon einer mit derselben Funktion existiert.
Wenn du die Quelle angeben kannst, könnte man mal schauen, ob da jemand Käse erzählt hat, oder ob du nur was falsch verstanden hast. Vermutlich hast du irgendwas von "einen eigenen TableModelListener erstellen" gelesen, und das so interpretiert, dass du ein eigenes interface erstellen sollst, anstatt nur das schon vorhandenen interface geeignet zu implementieren.
Zum Rest: so wie es aussieht, gibt es bei dir zum Thema Instanzen, static und Vererbung noch ein paar Verständnisprobleme. Was als erstes auffällt, ist, das AbstractTableModel zwar DefaultTableModel erweitert, aber keine der Methoden überschreibt und auch nirgendwo mit super Methoden aus DefaultTableModel-Klasse aufruft.
In sehe in deinem bisher geposteten Code zwei Instanzen von TableModel und JTable:
1. In deiner Klasse MainWindowView gibt es die Instanzvariable table vom Typ JTable. Deren Model ist eine anonyme Instanz von deinem AbstractTableModel. Die table wird zwar der Gui hinzugefügt, aber ihr Model (die anonyme AbstractTableModel-Instanz) enthält keine Daten!
2. In deiner AbstractTableModel-Klasse gibt es die Klassenvariablen tableModel vom Type DefaultTableModel und table vom Typ JTable. table verwendet tableModel als TableModel. AbstractTableModel.tableModel wird zwar mit Daten befüllt, aber AbstractTableModel.table wird nirgendwo einer Gui hinzugefügt.
 

CrookedPanda

Mitglied
Zum Rest: so wie es aussieht, gibt es bei dir zum Thema Instanzen, static und Vererbung noch ein paar Verständnisprobleme. Was als erstes auffällt, ist, das AbstractTableModel zwar DefaultTableModel erweitert, aber keine der Methoden überschreibt und auch nirgendwo mit super Methoden aus DefaultTableModel-Klasse aufruft.

Die Variablen und die Methode sind auch nur auf static gestellt, weil das meine Umgebung so brauchte, um nicht Fehler zu scheißen, z.b. dass versucht wird auf eine non-static method zuzugreifen.
Wegen der Vererbung war ich mir nicht sicher, ob ich Methoden überhaupt überschreiben soll. Manche Beispiele hatten selbst erstelle Methoden, andere diese vererbten Methoden, aber ich sehe bei mir nicht weshalb ich vererbte Methoden überschreiben muss. Ich habe ja so schon alles um die Tabelle zu befüllen.

In sehe in deinem bisher geposteten Code zwei Instanzen von TableModel und JTable:
1. In deiner Klasse MainWindowView gibt es die Instanzvariable table vom Typ JTable. Deren Model ist eine anonyme Instanz von deinem AbstractTableModel. Die table wird zwar der Gui hinzugefügt, aber ihr Model (die anonyme AbstractTableModel-Instanz) enthält keine Daten!

Die Tabelle soll beim Erstellen auch noch keine Daten enthalten, diese sollen erst später nach einer Suchanfrage aus der Datenbank ausgelesen werden und dann die Tabelle befüllen.

2. In deiner AbstractTableModel-Klasse gibt es die Klassenvariablen tableModel vom Type DefaultTableModel und table vom Typ JTable. table verwendet tableModel als TableModel. AbstractTableModel.tableModel wird zwar mit Daten befüllt, aber AbstractTableModel.table wird nirgendwo einer Gui hinzugefügt.

Und wie füge ich diese der View hinzu? Soweit ich über das MVC Pattern Bescheid weiß, sollten View und Models nicht direkt miteinander kommunizieren.

Ich verstehe noch immer nicht wie die Lösung für mein Problem code-technisch ausschaut. Ich verzweifle so langsam daran, dass es nirgendwo Beispiele zum Befüllen einer einfachen JTable nach MVC Pattern gibt und es mir auch niemand erklären kann.
 

Harry Kane

Top Contributor
Die Variablen und die Methode sind auch nur auf static gestellt, weil das meine Umgebung so brauchte, um nicht Fehler zu scheißen, z.b. dass versucht wird auf eine non-static method zuzugreifen.
Wenn du mal beschreiben würdest, wie du auf die statischen Variablen zugreifst, könnte ich erklären, wie man es besser machen kann.
Wegen der Vererbung war ich mir nicht sicher, ob ich Methoden überhaupt überschreiben soll.
Entweder Methoden überschreiben oder neue hinzufügen. Wenn beides nicht erwünscht ist, kann man sich das vererben sparen. Von daher ist es auch überflüssig, MainWindowView JFrame erweitern zu lassen, solange MainWindowView nur methoden von JFrame aufruft und weder Methoden überschreibt noch neue Funktionaalität hinzufügt, aber dieses Fass wollte ich nicht auch noch aufmachen.
Und wie füge ich diese der View hinzu?
Puh. Du hast doch schon zwei Beispiele in deinem Code, wo du einer JTable (der View) ein TableModel (das Model) verpasst: entweder du übergibst das Model im Konstruktor der JTable (so wie du es zweimala in deinem Code gemacht hast), oder mittels jtable.setModel(tableModel). Zumindest den getter für das TableModel einer JTable hast du ja auch schon verwendet.
Soweit ich über das MVC Pattern Bescheid weiß, sollten View und Models nicht direkt miteinander kommunizieren.
Was soll dieser Kommentar an dieser Stelle? Ich dachte wir reden hier über ein konkretes Problem, und du fängst hier mit allgemeinen Anmerkungen zu Programmdesign-Kriterien an.
Ich verstehe noch immer nicht wie die Lösung für mein Problem code-technisch ausschaut.
Poste mal den Code, so wie er jetzt ausschaut. Dann kann man konkretes dazu sagen. Vorab: ich sehe zwei Lösungen: 1. die quick and dirty Methode (nur damit es mal läuft) oder 2. die saubere Lösung.
Die erste Methode, angewandt auf deinen Code aus dem Eingangspost, würde darin bestehn, in deiner MainWindowView diesen Aufruf
Java:
this.add(new JScrollPane(table));
durch das hier zu ersetzen:
Java:
this.add(new JScrollPane(AbstractTableModel.updateTable));
, wobei du eine DatenbankDaoImpl-Instanz ohne DatenbankBeans übergeben musst.
Wenn das soweit läuft, können die anderen bugs angegangen werden. Eine Sache, die so bestimmt nicht gedacht war, ist es, bei jedem Aufruf von AbstractTableModel.updateTable dem TableModel einen neuen TableModelListener zu verwenden.
 

CrookedPanda

Mitglied
Wenn du mal beschreiben würdest, wie du auf die statischen Variablen zugreifst, könnte ich erklären, wie man es besser machen kann.

Ich habe nun versucht ein Objekt vom Typ JTable an den Controller zurückzugeben, also schaut es im Moment so aus:

Zugriff vom Model aus:
Java:
public JTable checkUser() {
        JTable nutzerrechtetabelle1 = new JTable();
        try {
            DatenbankDaoImpl db = new DatenbankDaoImpl();
            nutzerrechtetabelle1 = MyTableModel.updateTable(db);
        } catch (SQLException e) {
            logger.error(e);
        } catch (IOException e) {
            logger.error(e);
        }
        return nutzerrechtetabelle1;
    }

Und diese Methode wird im Controller aufgerufen:
Java:
case MainWindowView.CHECKUSER:
                if (MainWindowView.getUsername().trim().isEmpty()) {
                    logger.error("Bitte Nutzernamen angeben");

                } else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Nutzerrechte werden ausgelesen");
                    }
                    nutzerrechtetabelle1 = mainwindowmodel.checkUser();
                }
Nun weiß ich jetzt nur wieder nicht wie ich diese von hier der View so übergebe, dass die bestehende Tabelle "überschrieben"/aktualisiert wird.

Entweder Methoden überschreiben oder neue hinzufügen. Wenn beides nicht erwünscht ist, kann man sich das vererben sparen. Von daher ist es auch überflüssig, MainWindowView JFrame erweitern zu lassen, solange MainWindowView nur methoden von JFrame aufruft und weder Methoden überschreibt noch neue Funktionaalität hinzufügt, aber dieses Fass wollte ich nicht auch noch aufmachen.
Sorry, hier gab es wohl ein Missverständnis. Ich dachte es ging um das TableModel.

Puh. Du hast doch schon zwei Beispiele in deinem Code, wo du einer JTable (der View) ein TableModel (das Model) verpasst: entweder du übergibst das Model im Konstruktor der JTable (so wie du es zweimala in deinem Code gemacht hast), oder mittels jtable.setModel(tableModel). Zumindest den getter für das TableModel einer JTable hast du ja auch schon verwendet.

Aber doch nicht korrekt? Die Table wird ja nie aktualisiert angezeigt. Wie übergebe ich die jetzt entweder vom Controller oder direkt vom TableModel (wenn das besser ist)?

Poste mal den Code, so wie er jetzt ausschaut. Dann kann man konkretes dazu sagen. Vorab: ich sehe zwei Lösungen: 1. die quick and dirty Methode (nur damit es mal läuft) oder 2. die saubere Lösung.
Die erste Methode, angewandt auf deinen Code aus dem Eingangspost, würde darin bestehn, in deiner MainWindowView diesen Aufruf
Java:
this.add(new JScrollPane(table));
durch das hier zu ersetzen:
Java:
this.add(new JScrollPane(AbstractTableModel.updateTable));
, wobei du eine DatenbankDaoImpl-Instanz ohne DatenbankBeans übergeben musst.
Wenn das soweit läuft, können die anderen bugs angegangen werden. Eine Sache, die so bestimmt nicht gedacht war, ist es, bei jedem Aufruf von AbstractTableModel.updateTable dem TableModel einen neuen TableModelListener zu verwenden.

Hier ist jetzt mal der Code von View und TableModel soweit ich ihn aktualisiert habe:

TableModel:
Java:
public class MyTableModel extends DefaultTableModel {

    /**
     *
     */
    private static final long serialVersionUID = -7354466553311529134L;

    private static Logger logger = Logger.getLogger(MyTableModel.class);

    private static String col[] = { "Tabelle", "UpdateCols", "AlterAuth",
            "DeleteAuth", "IndexAuth", "InsertAuth", "SelectAuth", "UpdateAuth" };

    private static DefaultTableModel tableModel = new DefaultTableModel(null,
            col);
    private static JTable nutzerrechtetabelle = new JTable(tableModel);
 
    public MyTableModel() {
    
    }

    public static JTable updateTable(DatenbankDaoImpl db) throws SQLException,
            IOException {

        nutzerrechtetabelle.getModel().addTableModelListener(
                new TableModelListener() {

                    public void tableChanged(TableModelEvent e) {
                        logger.debug(e);
                    }
                });

        while (nutzerrechtetabelle.getRowCount() > 0) {
            ((DefaultTableModel) nutzerrechtetabelle.getModel()).removeRow(0);
        }

        for (DatenbankBean db1 : db.getDatenbank()) {
            String tabelle = db1.getTabelle();
            String updatecols = db1.getUpdatecols();
            String alterauth = db1.getAlterauth();
            String deleteauth = db1.getDeleteauth();
            String indexauth = db1.getIndexauth();
            String insertauth = db1.getInsertauth();
            String selectauth = db1.getSelectauth();
            String updateauth = db1.getUpdateauth();

            Object[] data = { tabelle, updatecols, alterauth, deleteauth,
                    indexauth, insertauth, selectauth, updateauth };
            tableModel.addRow(data);
            logger.debug("AbstractTableModel: " + data.toString());
        }
        tableModel.fireTableDataChanged();
        return nutzerrechtetabelle;
    }

}

Java:
public class MainWindowView extends JFrame {

    /**
     *
     */
    private static final long serialVersionUID = 3690599372483360842L;
 
    public static final String CHECKUSER = "CHECKUSER";
    private JButton checkuserbutton = new JButton("Testen");
    private static JTextField username = new JTextField(10);
    private JScrollPane scrollPane1 = new JScrollPane(nutzerrechtetabelle1);

//Konstruktor
    public MainWindowView(MainWindowModel model) {
        super();
        JPanel content = new JPanel();
        content.setLayout(new FlowLayout());
        //Auslesen von Nutzerrechten
        content.add(username);
        content.add(checkuserbutton);
    
        checkuserbutton.setActionCommand(CHECKUSER);
    
        this.setContentPane(content);
        nutzerrechtetabelle1.setPreferredScrollableViewportSize(new Dimension(500, 70));
        this.add(scrollPane1);
//        this.add(new JScrollPane(nutzerrechtetabelle1));
//        nutzerrechtetabelle1.getModel().addTableModelListener(nutzerrechtetabelle1);
        this.setExtendedState(JFrame.MAXIMIZED_BOTH);
        this.setTitle("Datenbank Administrationstool");
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
    public static String getUsername() {
        return username.getText();
    }
    public void addMainWindowListener(ActionListener listener) {
        checkuserbutton.addActionListener(listener);
    }
}
 

Harry Kane

Top Contributor
Sorry, hier gab es wohl ein Missverständnis. Ich dachte es ging um das TableModel.
Es geht auch um das TableModel. Sobald du eine Klasse erweiterst, ohne neue Methoden hinzuzufügen oder vorhandenen Methoden zu überschreiben, solltest du prüfen, ob das erweitern wirklich notwendig ist.
Zu deinem Code:Wie sieht die Klasse komplett aus, von der du den Codeausschnitt beginnend mit "case MainWindowView.CHECKUSER" gepostet hast? Und wie sieht die MainWindowModel-Klasse aus aus, von der offenbar eine Instanz in der o.g. Klasse rumschwirrt?
Grundsätzlich verknüpfe ich die verschiedenen Programmteile immer so, dass keine Gui-Elemente herumgereicht werden, sondern nur Model-Klassen.
Auf die Schnelle kannst du deine MyTableModel-Klasse zu einer funktionsfähigen TableModel-Klasse machen
- Attribut "static" bei col entfernen
- Konstruktor von MyTableModel um die Zeile ergänzen: super(null,col)
- statische Variablen tableModel und nutzerrechtetabelle entfernen.
-Attribut "static" bei der updateTable-Methode ändern, Rückgabewert auf void setzen.
- In der updateTable-Methode von MyTableModel
Java:
while (nutzerrechtetabelle.getRowCount() > 0) {
    ((DefaultTableModel) nutzerrechtetabelle.getModel()).removeRow(0);
}
ändern auf
Java:
while (getRowCount() > 0) {
    removeRow(0);
}
und tableModel.addRow(data) ändern zu addRow(data)
- Der Klasse mit der checkUser-Methode eine Referenz auf die MyTableModel-Instanz verpassen und die updateTable(db)-Methode der Instanz aufrufen anstatt die der Klasse.
 

CrookedPanda

Mitglied
Danke habe soweit mal die Änderungen übernommen, aber muss
Java:
private String col[] = { "Tabelle", "UpdateCols", "AlterAuth",
            "DeleteAuth", "IndexAuth", "InsertAuth", "SelectAuth", "UpdateAuth" };
nicht auf static stehen, damit ich es auch im Konstruktor verwenden kann?
Allerdings habe ich jetzt noch immer das Problem, dass meine Table nicht aktualisiert. Aber sie lädt wenigstens schon die Tabellen Header beim Erzeugen der GUI. Die tableChanged() Methode wird definitiv aufgerufen. Mein logger meldet mir bei jeder neuen row die hinzugefügt wird, dass diese Methode aufgerufen wird, aber in der View lässt sich noch immer nichts von den Daten sehen.

Der aktuelle Code des TableModels:
Java:
public class MyTableModel extends DefaultTableModel {

    /**
     *
     */
    private static final long serialVersionUID = -7354466553311529134L;

    private static Logger logger = Logger.getLogger(MyTableModel.class);

    private static String col[] = { "Tabelle", "UpdateCols", "AlterAuth",
            "DeleteAuth", "IndexAuth", "InsertAuth", "SelectAuth", "UpdateAuth" };
 
    public MyTableModel() {
        super(null,col);
    }

    public void updateTable(DatenbankDaoImpl db) throws SQLException,
            IOException {

        addTableModelListener(new TableModelListener() {
       
            @Override
            public void tableChanged(TableModelEvent e) {
                logger.debug("JTable changed");
            }
        });

        while (getRowCount() > 0) {
            removeRow(0);
        }

        for (DatenbankBean db1 : db.getDatenbank()) {
            String tabelle = db1.getTabelle();
            String updatecols = db1.getUpdatecols();
            String alterauth = db1.getAlterauth();
            String deleteauth = db1.getDeleteauth();
            String indexauth = db1.getIndexauth();
            String insertauth = db1.getInsertauth();
            String selectauth = db1.getSelectauth();
            String updateauth = db1.getUpdateauth();

            Object[] data = { tabelle, updatecols, alterauth, deleteauth,
                    indexauth, insertauth, selectauth, updateauth };
            addRow(data);
            logger.debug("AbstractTableModel: " + data.toString());
        }
        //fireTableDataChanged();
    }

}
 
Zuletzt bearbeitet:

Harry Kane

Top Contributor
nicht auf static stehen, damit ich es auch im Konstruktor verwenden kann?
Nein. static brauchst du nur, wenn du Variablen und Methoden ausserhalb einer bestimmten Instanz verwenden möchtest. Im Konstruktor wird aber gerade eine neue Instanz gebaut, so dass nicht-statische Variablen verfügbar sind. Bitte lerne beider nächsten Gelegenheit noch ein paar Grundlagen.
Deine neue MyTableModel - Klasse sieht schon mal gut aus.
Die tableChanged() Methode wird definitiv aufgerufen. Mein logger meldet mir bei jeder neuen row die hinzugefügt wird, dass diese Methode aufgerufen wird, aber in der View lässt sich noch immer nichts von den Daten sehen.
Klingt so, als wäre die MyTableModel-Instanz, auf der du die updateTable-Methode aufrufst, nicht die die in der View zu sehen ist. Zeige mal mehr Code, aus derm hervorgeht, wie die View bzw. die JTable darin gebaut wird bzw. mit welcher MyTableModel-Instanz, und wer wie die updateTable-Methode auf welcher MyTableModel-Instanz aufruft.
 

CrookedPanda

Mitglied
Nein. static brauchst du nur, wenn du Variablen und Methoden ausserhalb einer bestimmten Instanz verwenden möchtest. Im Konstruktor wird aber gerade eine neue Instanz gebaut, so dass nicht-statische Variablen verfügbar sind. Bitte lerne beider nächsten Gelegenheit noch ein paar Grundlagen.
Ich setze auch sonst nie statics, außer wenn nötig, aber hier schmeißt mir die Umgebung einen Fehler entgegen, dass die Variable static sein muss im Konstruktor.

Klingt so, als wäre die MyTableModel-Instanz, auf der du die updateTable-Methode aufrufst, nicht die die in der View zu sehen ist. Zeige mal mehr Code, aus derm hervorgeht, wie die View bzw. die JTable darin gebaut wird bzw. mit welcher MyTableModel-Instanz, und wer wie die updateTable-Methode auf welcher MyTableModel-Instanz aufruft.

Java:
public class MainWindowView extends JFrame {

    /**
     *
     */
    private static final long serialVersionUID = 3690599372483360842L;
 
    public static final String CHECKUSER = "CHECKUSER";
 
    private JButton checkuserbutton = new JButton("Testen");
    private static JTextField username = new JTextField(10);
    private JTable nutzerrechtetabelle1 = new JTable(new MyTableModel());
    private JScrollPane scrollPane1 = new JScrollPane(nutzerrechtetabelle1);
    private JScrollPane scrollPane2 = new JScrollPane(nutzerrechtetabelle2);

    //Konstruktor
    public MainWindowView(MainWindowModel model) {
        super();
        JPanel content = new JPanel();
        content.setLayout(new FlowLayout());
        //Auslesen von Nutzerrechten
        content.add(username);
        content.add(checkuserbutton);

        checkuserbutton.setActionCommand(CHECKUSER);
     
        this.setContentPane(content);
        nutzerrechtetabelle1.setPreferredScrollableViewportSize(new Dimension(800, 100));
        this.add(scrollPane1);
        this.setExtendedState(JFrame.MAXIMIZED_BOTH);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
 
    public static String getUsername() {
        return username.getText();
    }
    public void addMainWindowListener(ActionListener listener) {
        checkuserbutton.addActionListener(listener);
    }
Java:
private MainWindowModel mainwindowmodel;
    private MainWindowView mainwindowview;
    private static Logger logger = Logger.getLogger(MainWindowController.class);

    // Konstruktor
    public MainWindowController(MainWindowModel model, MainWindowView view) {
        this.mainwindowmodel = model;
        this.mainwindowview = view;

        // Listener hinzufügen
        view.addMainWindowListener(new MainWindowListener());
    }

    // inner class
    class MainWindowListener implements ActionListener {

        public void actionPerformed(ActionEvent e) {
            switch (e.getActionCommand()) {

            case MainWindowView.CHECKUSER:
                if (MainWindowView.getUsername().trim().isEmpty()) {
                    logger.error("Bitte Nutzernamen angeben");

                } else {
                    if (logger.isDebugEnabled()) {
                        logger.debug("Nutzerrechte werden ausgelesen");
                    }
                    mainwindowmodel.checkUser();
                }

                break;

            }

        }

    }

}
Java:
public class MainWindowModel {

    // Datenbanken später in Property Datei auslagern
    private String[] datenbanken = new String[] { "DSNT", "BIDIDA" };

    private static Logger logger = Logger.getLogger(MainWindowModel.class);

    public void checkUser() {
        MyTableModel mytable = new MyTableModel();
        try {
            DatenbankDaoImpl db = new DatenbankDaoImpl();
            mytable.updateTable(db);
          
            //Das hier sind nur alte Überbleibsel, später löschen
           
//            StringBuilder sb = new StringBuilder();
//            for (DatenbankBean db1 : db.getDatenbank()) {
//                sb.append(db1.getTabelle());
//                sb.append(db1.getUpdatecols());
//                sb.append(db1.getAlterauth());
//                sb.append(db1.getDeleteauth());
//                sb.append(db1.getIndexauth());
//                sb.append(db1.getInsertauth());
//                sb.append(db1.getSelectauth());
//                sb.append(db1.getUpdateauth());
//                sb.append(";");
//            }
//            String[] output = sb.toString().split(";");
//            for (String s : output) {
//                if (logger.isDebugEnabled()) {
//                    logger.debug(s);
//                }
//            }
        } catch (SQLException e) {
            logger.error(e);
        } catch (IOException e) {
            logger.error(e);
        }
    }
}
 

Harry Kane

Top Contributor
aber hier schmeißt mir die Umgebung einen Fehler entgegen, dass die Variable static sein muss im Konstruktor
Das Verhalten ist für mich absolut unverständlich. Gerade beim Konstruktor ist sichergestellt, dass wir eine Instanz haben bzw. gerade dabei sind, eine zu machen, und dann wird kein static gebraucht.

Vorab: wie vermutet, ist die MyTableModel-Instanz, auf der die updateTable-methode aufgrufen wird, nicht die, die zum Aufbau einer sichtbaren JTable dient. Du legst nämlich in der checkUser-Methode immer eine neue MyTableModel-Instanz an, die am Ende der Methode nicht mehr gebraucht wird und bei der nächsten Gelegenheit vom gc abgeräumt werden sollte.

MainWindowModel ist m. E. kein Model, weil es keine Daten enthält. Es weisst das MyTableModel lediglich an, sich neue Daten aus der db zu holen, wäre also eher ein Controller.

Ich finde Verknüpfung von MainWindowModel, MainWindowView und MainWindowController nicht gut gelöst. Eine Idee hinter dem MVC Konzept ist es, die Komponenten austauschbar zu machen, ohne existierenden Code anfassen zu müssen, ohne in den Model, View und Controller-Klasse unnötig Overhead rumzuschleppen, und ohne dass sich die Komponenten untereinander zu gut kennen müssen. Formal sind in deinem Code zwar Model, View und Controller getrennt, aber die ganzen Querbezüge zwischen den Klassen schränken die Wartbarkeit und Wiederverwendbarkeit stark ein. Deine Controller-Klasse macht im Prinzip auch nichts weiter als der View einen ActionListener hinzuzufügen und je nach ActionCommand eine Aktualisierung der Tabelle zu veranlassen. Dabei bedient sich der Controller mehrerer Variablen aus der View-Klasse, die dafür nach aussen zugänglich sein müssen. Wenn du auf verschiedene ButtonEvents reagieren möchtest, musst du jedesmal sowohl die View als auch den Controller anfassen und dafür sorgen, dass die ActionCommands und die aufgerufenen Methoden konsistent sind. Bei so wenig Funktionalität im Controller bei gleichzeitig so vielen Querbezügen ist m. E. eine extra Controller-Klasse überflüssig, sondern die Auswertung des Buttonklicks kann einfach über einen anonymen ActionListener erfolgen. Leider sieht man häufig Code, wo eine View JFrame erweitert und ein paar Komponenten enthält, es einen Controller gibt, der auf eine Komponente der View zugreifen muss, und deshalb die View mit einem Getter für die Komponente ausgestattet wird und die View komplett an den Controller übergeben wird, der sich dann bei Bedarf über den getter die benötigte Komponente aus der View holt und auswertet, aber sowas finde ich höchst unschön. Mag sein, dass so eine Architektur auf den ersten Blick den Anforderungen des MVC Pattern genügt, aber praktikabel finde ich es absolut nicht.

Hier mal ein Beispiel, wie stark man den Code vereinfachen kann. Ist gerade in einem Editor runterschrieben und deshalb weder auf Kompilierbarkeit noch Lauffähigkeit getestet.
Java:
public class MainWindowView extends JFrame {

    /**
     *
     */
    private static final long serialVersionUID = 3690599372483360842L;
    public static final String CHECKUSER = "CHECKUSER";
    private JButton checkuserbutton = new JButton("Testen");
    private JTextField username = new JTextField(10);//kein static!
   private MyTableModel model = new MyTableModel()
    private JTable nutzerrechtetabelle1 = new JTable(model);//Die MyTableModel-Instanz sollte nicht anonym sein, damit sie direkt zugänglich ist.
    private JScrollPane scrollPane1 = new JScrollPane(nutzerrechtetabelle1);
    private JScrollPane scrollPane2 = new JScrollPane(nutzerrechtetabelle2);//warum 2. JScrollPane??

    //Konstruktor
    public MainWindowView(MainWindowModel model) {
        super();
        JPanel content = new JPanel();
        content.setLayout(new FlowLayout());
        //Auslesen von Nutzerrechten
        content.add(username);
        content.add(checkuserbutton);

        checkuserbutton.setActionCommand(CHECKUSER);
       //ein anonymer ActionListener als Controller:
       //Benutzereingaben werden ausgewertet und  Änderung am Model ausgelöst.
        checkuserbutton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ae) {
               DatenbankDaoImpl db = new DatenbankDaoImpl();
               model.updateTable(db);
            }
        });
    
        this.setContentPane(content);
        nutzerrechtetabelle1.setPreferredScrollableViewportSize(new Dimension(800, 100));
        this.add(scrollPane1);
        this.setExtendedState(JFrame.MAXIMIZED_BOTH);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setVisible(true);
    }
}
Edit: hier mal ein Link zu einem Thread, wo ich mich schonmal zum Thema "Programmaufbau" geäussert habe: http://www.java-forum.org/thema/programmaufbau-in-ordnung-problem-mit-paintcomponent.176062/
 

CrookedPanda

Mitglied
Wenn ich das so implementieren würde, hätte ich doch aber Code in meiner View? Wozu brauche ich denn dann noch meinen Controller, wenn ich den weder für Listener noch für Funktionen, die darauf ausgeführt werden sollen, brauche?

Mir kommt es hier auch gar nicht auf das MVC Pattern an, sondern, dass ich einfach meine JTable hinbekomme. Das beim Einsetzen von Pattern was nicht so ist wie es sein soll, ist ja sowieso immer so. Ich würde gerne mein Problem lösen ohne mein halbes Programm umschreiben zu müssen.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
D MySQL Daten in JTable anzeigen AWT, Swing, JavaFX & SWT 2
A JTable mit Daten füllen AWT, Swing, JavaFX & SWT 1
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
C Daten aus DB -> JTable aktualisieren klappt nicht AWT, Swing, JavaFX & SWT 16
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
L Swing Daten in JTable aktualisieren AWT, Swing, JavaFX & SWT 5
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 aktualisieren 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