Swing AbstractTableModel

Zeppi

Aktives Mitglied
Moin, ich versuche gerade ein JTable zu füllen mit einer ArrayList. Bei meinem Programm ist es so, dass man immer gefragt wird, was eingegeben werden soll, das wird in der ArrayList gespeichert. In der ArrayList steht dann immer ein Name und eine Zeit. Aber wenn ich dann damit versuche das 2d Array für den Table zufüllen, werden bei mir natürlich immer die Daten überschrieben und es steht dann in der Tabelle immer das Gleiche. Das liegt daran, das im JDialog immer eine neue Tabelle aufgerufen wird, dadurch fängt das 2d Array immer von vorne an und speichert dann den neusten Wert an jeder Position. Vielleicht kann jemand mal ein Blick drüber werfen und mir Tipps geben.

[CODE lang="java" title="JDialog"]public class HighDialog extends JDialog {

public HighDialog(String name, int zeit) {
JTable table = new JTable(new Tabelle(name, zeit)); //hier wird immer der neue JTable aufgerufen
table.setSize(400, 400);
add(new JScrollPane(table));
table.setVisible(true);
setSize(500, 500);
}
}[/CODE]
[CODE lang="java" title="AbstractTableModel"]public class Tabelle extends AbstractTableModel {
private Highscore highscore = Highscore.getInstance(); //ist ein Singleton und die ArrayList
final String[] spaltenBeschriftung = { "Spielername", "Zeit" };
final Object[][] data = new Object[10][2]; //größe der Tabelle

public Tabelle(String name, int zeit) { //bekommt die Werte vom JDialog übergeben
highscore.add(new Score(name, zeit)); //hier wird die ArrayList gefüllt mit einem Score. Score besteht aus einem String spielername und int Sekunden
for (int i = 0; i < highscore.size(); i++) { //dadurch, dass das immer von 0 beginnt, werden die ersten Werte des Arrays data überschrieben
for (Score s : highscore) { //hier wird jeder Score von Highscore durchlaufen

data[0] = s.getSielername(); //spielername wird gespeichert
data[1] = s.getSekunden(); //zeit des spieler werden gespeichert
}
}
}
}[/CODE]
[CODE lang="java" title="JPanel"]//wenn mein Spiel gewonnen wurde, wird das durchgeführt
String name = JOptionPane.showInputDialog(this, "Name");
if (name != null) {
Highdialog dia = new HighDialog(name,zeit); //hier wird name und zeit dem Dialog übergeben,
//weil ich nicht wusste, wie sonst die Tabelle die Werte bekommt,
//damit die ArrayList gefüllt wird.
dia.setVisible(true);[/CODE]

Vielleicht hat jemand ein Tipp bzw. Verbesserungen.
Danke Zeppi
 
Gib dem Konstruktor von HighDialog doch einfach eine Instanz von Tabelle mit, dann brauchst Du diese im Konstruktor nicht neu zu erzeugen.
 
Gib dem Konstruktor von HighDialog doch einfach eine Instanz von Tabelle mit, dann brauchst Du diese im Konstruktor nicht neu zu erzeugen.
Meinst du so?
Java:
public class HighDialog extends JDialog {
    private Highscore highscore = Highscore.getInstance();
    private Tabelle tabelle = new Tabelle();

    public HighDialog(String name, int zeit) {
        highscore.add(new Score(name, zeit));
        JTable table = new JTable(tabelle);
        table.setSize(400, 400);
        add(new JScrollPane(table));
        table.setVisible(true);
        setSize(500, 500);
 
Zuletzt bearbeitet:
Nein, ich meine so:
Java:
public class HighDialog extends JDialog {

    public HighDialog(Tabelle tabelle) {
        JTable table = new JTable(tabelle);
        table.setSize(400, 400);
        add(new JScrollPane(table));
        table.setVisible(true);
        setSize(500, 500);
    }
}
Achso, aber da verändert sich nicht wirklich etwas. Wenn ich jetzt zwei unterschiedliche Namen hintereinander eingebe, haben beide Einträge die selben Daten.
 
Doch, da verändert sich sehr viel: Du erzeugst nun keine neue Tabellen-Instanz mehr. Das Problem, das Du ansprichst, ist auf etwas anderes zurückzuführen. Vermutlich willst Du in Deinem TableModel noch eine add-Methode einführen, um eine übergebene Highscore in der Liste einzutragen.
 
Doch, da verändert sich sehr viel: Du erzeugst nun keine neue Tabellen-Instanz mehr. Das Problem, das Du ansprichst, ist auf etwas anderes zurückzuführen. Vermutlich willst Du in Deinem TableModel noch eine add-Methode einführen, um eine übergebene Highscore in der Liste einzutragen.
Genau! Ich habe es ja mit dem Konstruktor versucht. Aber dadurch fängt die Liste immer von vorne an und überschreibt die Daten.
 
Es gibt verschiedene Möglichkeiten, das hängt davon ab, wie die Aktualisierung im UI stattfinden soll. Ich gehe mal davon aus, dass Du eine Tabelle anzeigst und in einem Dialog willst Du der Tabelle nun eine Zeile hinzufügen.

Wenn Highscore außer einer popligen List nichts bietet, dann muss die JTable und Dein Dialog das selbe TableModel verwenden, das seinerseits eine add-Implementierung anbietet. Der Dialog ruft dann einfach dieses add auf und die JTable zeigt die Änderung automatisch an. BTW: die Highscore braucht kein Singleton zu sein.
 
Hier mal im Zusammenhang:
Java:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.table.*;

public class Test {
    // Kurze Implementierung, damit wir was zu zeigen haben
    static class Score {
        public final String name;
        public final int points;

        public Score(String name, int points) {
            this.name = name;
            this.points = points;
        }
    }

    static class ScoreTable extends AbstractTableModel {
        private static final String[] COLUMNS = {
            "Name", "Punkte"
        };

        private List<Score> scores;

        public ScoreTable(List<Score> scores) {
            this.scores = scores;
        }

        // hier die add-Methode
        public void add(Score score) {
            int newIndex = 0;
            int numRows = getRowCount();
            while (newIndex < numRows && 
                    score.points < scores.get(newIndex).points) {
                newIndex++;
            }
            
            scores.add(newIndex, score);
            fireTableRowsInserted(newIndex, newIndex);
        }

        @Override public int getRowCount() { return scores.size(); }
        @Override public int getColumnCount() { return COLUMNS.length; }
        @Override public String getColumnName(int col) { return COLUMNS[col]; }
        @Override public Object getValueAt(int row, int col) {
            Score score = scores.get(row);
            switch(col) {
                case 0: return score.name;
                case 1: return Integer.toString(score.points);
            }
            return "";
        }
    }

    // wir haben nur eine Instanz der Highscores
    private List<Score> highscore = new ArrayList<>();
    private ScoreTable scores = new ScoreTable(highscore);

    public void newHighScore() {
        final JTextField nameField = new JTextField(50);
        final JTextField pointsField = new JTextField();
        JPanel panel = new JPanel(new GridLayout(0,1));
        panel.add(new JLabel("Name:"));
        panel.add(nameField);
        panel.add(new JLabel("Punkte:"));
        panel.add(pointsField);

        boolean valid;  
        do {
            valid = true;
            int result = JOptionPane.showConfirmDialog(null, panel, 
                "Neue Highscore", JOptionPane.OK_CANCEL_OPTION);
            if (result == JOptionPane.OK_OPTION) {
                try {
                    String name = nameField.getText();
                    int points = Integer.parseInt(pointsField.getText());
                    scores.add(new Score(name, points)); // zur Highscore-Tabelle hinzufügen
                } catch (NumberFormatException ex) {
                    valid = false;
                }
            }
        } while (!valid);
        
    }

    public void run() {
        JTable table = new JTable(scores); // highscores in Tabelle anzeigen
        JButton button = new JButton("Neue Highscore");
        button.addActionListener(e -> newHighScore());

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(new JScrollPane(table));
        frame.add(button, BorderLayout.SOUTH);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
 
Hier mal im Zusammenhang:
Java:
import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.util.ArrayList;
import java.util.List;
import javax.swing.*;
import javax.swing.table.*;

public class Test {
    // Kurze Implementierung, damit wir was zu zeigen haben
    static class Score {
        public final String name;
        public final int points;

        public Score(String name, int points) {
            this.name = name;
            this.points = points;
        }
    }

    static class ScoreTable extends AbstractTableModel {
        private static final String[] COLUMNS = {
            "Name", "Punkte"
        };

        private List<Score> scores;

        public ScoreTable(List<Score> scores) {
            this.scores = scores;
        }

        // hier die add-Methode
        public void add(Score score) {
            int newIndex = 0;
            int numRows = getRowCount();
            while (newIndex < numRows &&
                    score.points < scores.get(newIndex).points) {
                newIndex++;
            }
           
            scores.add(newIndex, score);
            fireTableRowsInserted(newIndex, newIndex);
        }

        @Override public int getRowCount() { return scores.size(); }
        @Override public int getColumnCount() { return COLUMNS.length; }
        @Override public String getColumnName(int col) { return COLUMNS[col]; }
        @Override public Object getValueAt(int row, int col) {
            Score score = scores.get(row);
            switch(col) {
                case 0: return score.name;
                case 1: return Integer.toString(score.points);
            }
            return "";
        }
    }

    // wir haben nur eine Instanz der Highscores
    private List<Score> highscore = new ArrayList<>();
    private ScoreTable scores = new ScoreTable(highscore);

    public void newHighScore() {
        final JTextField nameField = new JTextField(50);
        final JTextField pointsField = new JTextField();
        JPanel panel = new JPanel(new GridLayout(0,1));
        panel.add(new JLabel("Name:"));
        panel.add(nameField);
        panel.add(new JLabel("Punkte:"));
        panel.add(pointsField);

        boolean valid; 
        do {
            valid = true;
            int result = JOptionPane.showConfirmDialog(null, panel,
                "Neue Highscore", JOptionPane.OK_CANCEL_OPTION);
            if (result == JOptionPane.OK_OPTION) {
                try {
                    String name = nameField.getText();
                    int points = Integer.parseInt(pointsField.getText());
                    scores.add(new Score(name, points)); // zur Highscore-Tabelle hinzufügen
                } catch (NumberFormatException ex) {
                    valid = false;
                }
            }
        } while (!valid);
       
    }

    public void run() {
        JTable table = new JTable(scores); // highscores in Tabelle anzeigen
        JButton button = new JButton("Neue Highscore");
        button.addActionListener(e -> newHighScore());

        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.add(new JScrollPane(table));
        frame.add(button, BorderLayout.SOUTH);
        frame.setSize(800, 600);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> new Test().run());
    }
}
Klasse. Danke für die ausführliche Beschreibung. Ich werde das gleich mal umbauen und bei mir versuchen.
 

Zurück
Oben