# Eigenes TableModel abgeleitet von AbstractTableModel (neue rows nicht sichtbar)



## Patric (14. Mrz 2009)

*Die Lösung des Problems befindet sich im dritten Post!*

Hallo zusammen,

ich sitze jetzt schon seit ein paar Stunden daran, mein TableModel dazu zu bewegen mir die Reihen, die ich zur Laufzeit hinzugefügt habe auch an zu zeigen. Bisher leider ohne Erfolg.

Die Daten als solches werden zwar in die Tabelle eingetragen, allerdings kann ich diese nicht sehen. Wenn ich jetzt z.B. zwei Reihen im Konstruktor meines Hauptprogramms zu der JTable hinzufüge, dann sehe ich diese nach dem start auch wunderbar. Sobald ich es allerdings zur Laufzeit versuche klappt es nicht mehr, sie werden dann nicht angezeigt. Das die Reihen, die ich zur Laufzeit hinzugefügt habe da sind habe ich überprüft, indem ich auf meine JTable geklickt habe und dann mit der Pfeil-nach-unten-Taste nach unten gegangen bin und die Selektion dann unter meiner JTable im Nichts verschwunden ist. Wenn ich das mache, ohne zur Laufzeit eine Reihe hinzugefügt zu haben, dann bleibt meine Selektion bei der zweiten Reihe stehen und ich sehe sie noch.

Ich habe mir hier in dem Forum schon mehrere Beiträge, sowie das Tutorial zum Thema JTable durchgelesen, konnte aber auch da nichts finden, was mir weiterhilft.

Mein TableModel leite ich von vom AbstractTableModel ab welches sich (laut Informationen die ich hier gefunden habe) selber darum kümmert, dass die JTable aktualisiert wird, sobald sich dort was getan hat. Da dies allerdings nicht der Fall zu sein scheint, habe ich auch mal die passenden fire-Methoden aufgerufen, nachdem ich etwas an der JTable gemacht habe, allerdings blieb auch das ohne Erfolg.

Hier jetzt mal der Code, ich bin sicher ihr könnt mir damit weiterhelfen:

Mein TableModel

[HIGHLIGHT="Java"]class DownloadTableModel extends AbstractTableModel
{

	private static final long serialVersionUID = 1L;
	String[] headers = {"ContentId", "Filename", "Size", "Progress"};
	@SuppressWarnings("unchecked")
	Class[] columnClasses = {String.class, String.class, String.class, JProgressBar.class};
	Vector<RowEntry> data = new Vector<RowEntry> ();

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

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

	@SuppressWarnings("unchecked")
	public Class getColumnClass(int c)
	{
		return columnClasses[c];
	}

	public String getColumnName(int c)
	{
		return headers[c];
	}

	public boolean isCellEditable(int r, int c)
	{
		return false;
	}

	@Override
	public Object getValueAt(int r, int c)
	{
		RowEntry e = data.get(r);
		switch (c)
		{
			case 0: return e.getContentId();
			case 1: return e.getFilename();
			case 2: return e.getSize();
			case 3: return e.getProgressBar().getValue();
			default: return null;
		}
	}

	public void setValueAt(Object value, int r, int c)
	{
	}

	public void addRow(String filename, String size)
	{
		int ID = getRowCount();

		data.add(new RowEntry(String.valueOf(ID), filename, size, createProgressBar()));
		fireTableRowsInserted(ID, ID); // Hier sage ich nochmal explizit, was ich hinzugefügt habe
	}

	public void removeRowAt(int r)
	{
	}

	private JProgressBar createProgressBar()
	{
		JProgressBar pb = new JProgressBar(0, 100);
		pb.setValue(0);
		pb.setStringPainted(true);
		return pb;
	}
}[/HIGHLIGHT]



Mein TableCellRenderer:

[HIGHLIGHT="Java"]class DownloadTableRenderer extends JProgressBar implements TableCellRenderer
{

	private static final long serialVersionUID = 1L;

	public DownloadTableRenderer()
	{
		super(SwingConstants.HORIZONTAL);
		this.setSize(115, 15);
	}

	@Override
	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column)
	{
		if (value == null)
			return this;
		if (value instanceof JProgressBar)
			setValue(((JProgressBar)value).getValue());
		else
			setValue(0);
		return this;
	}
}[/HIGHLIGHT]


Mfg. Patric


----------



## SlaterB (14. Mrz 2009)

> Das die Reihen, die ich zur Laufzeit hinzugefügt habe da sind habe ich überprüft, indem ich auf meine JTable geklickt habe und dann mit der Pfeil-nach-unten-Taste nach unten gegangen bin und die Selektion dann unter meiner JTable im Nichts verschwunden ist.

klingt nach einem Layoutproblem der JTable an sich, dazu hast du ja gar nix gepostet,
füge die JTable vielleicht in ein JScrollPane ein, dann bekommst du ScrollBalken?


----------



## Patric (14. Mrz 2009)

SlaterB hat gesagt.:


> > Das die Reihen, die ich zur Laufzeit hinzugefügt habe da sind habe ich überprüft, indem ich auf meine JTable geklickt habe und dann mit der Pfeil-nach-unten-Taste nach unten gegangen bin und die Selektion dann unter meiner JTable im Nichts verschwunden ist.
> 
> klingt nach einem Layoutproblem der JTable an sich, dazu hast du ja gar nix gepostet,
> füge die JTable vielleicht in ein JScrollPane ein, dann bekommst du ScrollBalken?



Die JTable befindet sich bereits in einem JScrollPane. Mein Hauptframe hat folgende Größe:

[HIGHLIGHT=Java]private final Dimension SIZE = new Dimension(650, 450);[/HIGHLIGHT]

und hat ein 1x1 großes Grid Layout.

[HIGHLIGHT=Java]
this.setLayout(new GridLayout(1, 1));
dlGrid = new DownloadGrid();
this.add(new JScrollPane(dlGrid));
[/HIGHLIGHT]

Ich füge im Konstruktor auch nur 2 Reihen ein, es ist also noch genügend Platz für weitere Reihen.

Hier mal ein Screenshot:







*Nachtrag:*

Ich habe jetzt mal die Methode removeRowAt vervollständigt:

[HIGHLIGHT=Java]
	public void removeRowAt(int r)
	{
		data.removeElementAt(r);
		fireTableRowsDeleted(r, r);
	}
[/HIGHLIGHT]

Wenn ich jetzt zur Laufzeit ein Element entferne, dann sieht das wie folgt aus:






Hier sieht es so aus, als würde das neu zeichnen da nicht so ganz funktionieren.

*addRow geändert*

Ich habe meine addRow-Methode mal so umgeschrieben, dass ich die Listener alle manuell benachrichtige, allerdings wieder ohne Erfolg

[HIGHLIGHT=Java]
	public void addRow(String filename, String size)
	{
		int ID = getRowCount();

		data.add(new RowEntry(String.valueOf(ID), filename, size, createProgressBar()));
//		fireTableRowsInserted(ID, ID);
		TableModelListener[] tmls = (TableModelListener[])(this.getListeners(TableModelListener.class));
		for (TableModelListener l : tmls)
		{
			TableModelEvent e = new TableModelEvent(this, ID, ID, TableModelEvent.ALL_COLUMNS,
					TableModelEvent.INSERT);

			l.tableChanged(e);
		}
	}
[/HIGHLIGHT]

Okay, ich habe das Problem gelöst. Eigentlich war es klar, dass man da zuerst mal gucken sollte. Ich habe in meine Hauptklasse das TableModelInterface implementiert. Die tableChanged-Methode habe ich allerdings leer gelassen (aus welchen Grund auch immer^^). Jetzt habe ich sie wie folgt geändert und es funktioniert. Jetzt kann ich auch zur Laufzeit Daten hinzufügen.

[HIGHLIGHT=Java]
public void tableChanged(TableModelEvent e)
	{
		super.tableChanged(e);
	}
[/HIGHLIGHT]

Allerdings habe ich jetzt ein neues Problem. Ich habe auf einmal doppelt so viele Spalten, wie ich eigentlich habe (Jede 2 mal).
Dabei spielt es keine Rolle, wann ich die Daten hinzufüge.

Wenn ich jetzt die Zeile 
[HIGHLIGHT=Java]super.tableChanged(e);[/HIGHLIGHT]
auskommentiere, dann hab ich nur die 4 Spalten, die ich auch tatsächlich habe.

Kann damit jemand was anfangen?

Mfg. Patric


----------



## SlaterB (14. Mrz 2009)

was für ein ewiges Mysterium, unvollständigen Code zu posten, und auch schön in kleine Teile zerstückelt,
alles darf man sich zusammenkopieren, 
zusätzliche Klassen wie DownloadGrid oder RowEntry oder gar überhaupt ein JFrame/ eine Main-Methode selbst ausdenken

ich habe mir deine Teile so weit es geht zusammenkopiert und nichts deutet auf ein Problem hin,
wollte erst Buttons zum Hinzufügen/ Entfernen verwenden, aber bei GridLayout(1,1) passt ja nun überhaupt nix weiter rein,
also einfach ein Skript: nach einer Sekunde werden zwei Zeilen hinzugefügt, später drei entfernt, alles klappt


so geht ein Programm: alles kopieren, einfügen, vielleicht noch imports ergänzen, auf Ausführen klicken, läuft

```
public class Test {

    private static final Dimension SIZE = new Dimension(650, 450);

    public static void main(String argv[]) throws Exception {

        JFrame f = new JFrame();
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        f.setSize(SIZE);
        f.setLayout(new GridLayout(1, 1));

        DownloadGrid dlGrid = new DownloadGrid();
        f.add(new JScrollPane(dlGrid));
        f.setVisible(true);

        Thread.sleep(1000);
        DownloadGrid.m.addRow("d", "e");
        DownloadGrid.m.addRow("d", "e");
        Thread.sleep(1000);
        DownloadGrid.m.removeRowAt(0);
        DownloadGrid.m.removeRowAt(0);
        DownloadGrid.m.removeRowAt(0);

        // JButton plus = new JButton("+");
        // plus.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // DownloadGrid.m.addRow("d", "e");
        // }
        //
        // });
        // JButton minus = new JButton("+");
        // minus.addActionListener(new ActionListener() {
        // public void actionPerformed(ActionEvent e) {
        // DownloadGrid.m.removeRowAt(0);
        // }
        //
        // });
        // JPanel buttons = new JPanel();
        // buttons.add(plus);
        // buttons.add(minus);

    }
}

class DownloadGrid extends JTable {

    public static final DownloadTableModel m = new DownloadTableModel();

    public DownloadGrid() {
        m.addRow("a", "b");
        m.addRow("c", "d");
        setModel(m);
    }
}

class RowEntry {

    private JProgressBar p;

    private String x;

    private String y;

    public RowEntry(String string, String filename, String size,
            JProgressBar bar) {
        p = bar;
        x = filename;
        y = size;
    }

    public Object getContentId() {
        return x;
    }

    public Object getFilename() {
        return y;
    }

    public Object getSize() {
        return null;
    }

    public JProgressBar getProgressBar() {
        return p;
    }

}

class DownloadTableModel extends AbstractTableModel {

    private static final long serialVersionUID = 1L;

    String[] headers = { "ContentId", "Filename", "Size", "Progress" };

    @SuppressWarnings("unchecked")
    Class[] columnClasses = { String.class, String.class, String.class,
            JProgressBar.class };

    Vector<RowEntry> data = new Vector<RowEntry>();

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

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

    @SuppressWarnings("unchecked")
    public Class getColumnClass(int c) {
        return columnClasses[c];
    }

    public String getColumnName(int c) {
        return headers[c];
    }

    public boolean isCellEditable(int r, int c) {
        return false;
    }

    @Override
    public Object getValueAt(int r, int c) {
        RowEntry e = data.get(r);
        switch (c) {
        case 0:
            return e.getContentId();
        case 1:
            return e.getFilename();
        case 2:
            return e.getSize();
        case 3:
            return e.getProgressBar().getValue();
        default:
            return null;
        }
    }

    public void setValueAt(Object value, int r, int c) {
    }

    public void addRow(String filename, String size) {
        int ID = getRowCount();

        data.add(new RowEntry(String.valueOf(ID), filename, size,
                createProgressBar()));
        fireTableRowsInserted(ID, ID); // Hier sage ich nochmal explizit, was
        // ich hinzugefügt habe
    }

    public void removeRowAt(int r) {
        data.removeElementAt(r);
        fireTableRowsDeleted(r, r);
    }

    private JProgressBar createProgressBar() {
        JProgressBar pb = new JProgressBar(0, 100);
        pb.setValue(0);
        pb.setStringPainted(true);
        return pb;
    }
}

class DownloadTableRenderer extends JProgressBar implements TableCellRenderer {

    private static final long serialVersionUID = 1L;

    public DownloadTableRenderer() {
        super(SwingConstants.HORIZONTAL);
        this.setSize(115, 15);
    }

    @Override
    public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int column) {
        if (value == null)
            return this;
        if (value instanceof JProgressBar)
            setValue(((JProgressBar) value).getValue());
        else
            setValue(0);
        return this;
    }
}
```

edit:
setDefaultRenderer(JProgressBar.class, new DownloadTableRenderer());

für den Renderer ändert auch nichts am Hinzufügen oder Entfernen von Zeilen


----------



## Patric (14. Mrz 2009)

Danke erstmal für deinen Einsatz =)

Habe nun auch das Problem mit den doppelten Spalten gelöst. War ein Dummer Fehler, ich habe die Spalten aus Versehen 2 mal hinzugefügt.

Zu dem Mysterium: Okay sehe ich ein, ab jetzt gibt es von mir nur noch KSKBś, mein Wort drauf 

Kurze Frage: Früher konnte man die Themen als gelöst markieren, geht das hier immernoch? Finde grad keine Button dazu.


----------



## SlaterB (14. Mrz 2009)

derzeit noch nicht in der neuen Forum-Software


----------



## freak4fun (17. Apr 2009)

Danke eucg! Ich hab das AbstractTableModel anhand dieses Beispiels verstanden.


----------

