JTable update was ist nun wieder falsch?

a400

Mitglied
Hallo, guten Abend, ich hab da ein Problem mit einem JTable. Ich habe mir einen Frame

erstellt und dort ein BorderLayout erstellt. So, dann hab ich in den Westen mein erzeugtes

DefaultTableModel gepackt und in den Süden 4 Buttons, die jeweils eine Aktion im JTable

durchführen sollen. Z.B. soll wenn der Button 2 gedrückt wird in einer Zelle eine bestimmte

Zahl gesetzt werden, nur leider klappt das nicht so wie es soll mit diesem

setValueAt(Object aValue, int rows, int cols).
Desweiteren bekomme ich bei dieser Methode eine Fehlermeldung ohne Lösungstipp:

public void fireTableCellUpdated(int row, int column)
{
fireTableChanged(new TableModelEvent(this, row, row, column));
}
Ich hab jetzt schon an allem herumgetrickst, aber finde keine Lösungsmöglichkeit, dass das

JTable hier die Zahl, die auf Knopfdruck gesetzt werden soll auch setzt, bzw im JTable dann

auch anzeigt. Kann mir jemand dabei helfen, das hinzubekommen, oder sich zumnidest mal

meinen Code anschauen und einfügen was ich ändern muss bzw. Tipps geben was daran falsch

ist. Danke

Code:
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableModel;
 
public class FrameTable extends JFrame implements ActionListener 
{
	private class MeinWindowListener extends WindowAdapter
	{
 
		public void windowClosing(WindowEvent arg0)
		{
			System.exit(0);
		}
	}
private String[] columnNamen = { "Möglichkeit 1", "Möglichkeit 2", "Möglichkeit 3, 
 
Möglichkeit 4"};
	private Object[][] Zahlen = {
{ new Integer(12), new Integer(2), new Integer(4), new Integer(6) 
 
},
{ new Integer(12), new Integer(4), new Integer(13), new Integer(9) 
 
},
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) }, 
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) }, 
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) }, 
{ new Integer(0), new Integer(0), new Integer(0), new Integer(0) }
	};
private DefaultTableModel tableModelM;
	private JButton b1, b2, b3, b4;
	private JComponent jc = (JComponent)getContentPane();
 
 
FrameTable()
{
	super();
		setTitle("FrameTable");
		setSize(800, 600);		
		initLayout();
		setLocationRelativeTo(null);
		addWindowListener(new MeinWindowListener());
		setVisible(true);
		setResizable(true);		
	}
 
	void initLayout()
	{
jc.setLayout( new BorderLayout( ) );
 
// JTable erstellen
	tableModelM = new DefaultTableModel(Zahlen, columnNamen );
 
JTable tableZahlen = new JTable(tableModelM);
tableZahlen.setAutoResizeMode( JTable.AUTO_RESIZE_OFF );
 
// tableSpieler einem Container zuführen 
JScrollPane scrollM = new JScrollPane (tableZahlen);
scrollM.setPreferredSize(new Dimension(300,300));
 
//West
JPanel wPnl = new JPanel();
wPnl.add("Center", scrollM);
jc.add("West", wPnl);
 
//South 
JButton b1 = new JButton("2");
b1.addActionListener(this);
JButton b2 = new JButton("4");
b2.addActionListener(this);
JButton b3 = new JButton("6");
b3.addActionListener(this);
JButton b4 = new JButton("8");
b4.addActionListener(this);
 
JPanel sPnl = new JPanel();
sPnl.add(b1);
sPnl.add(b2);
sPnl.add(b3);
sPnl.add(b4);
jc.add("South", sPnl);
 
 
	}
 
 
	public int getColumnCount() 
	{
		return columnNamen.length;
	}
 
	public int getRowCount() 
	{
		return Zahlen.length;
	}
 
	public String getColumnName(int col) 
	{
		return columnNamen[col];
	}
 
	public Object getValueAt(int row, int col) 
	{
		return Zahlen[row][col];
	}
 
	public Class getColumnClass(int c) 
	{
		return getValueAt(0, c).getClass();
	}
 
	public boolean isCellEditable(int row, int col) 
	{
		if (col < 4) 
		{
			return false;
		} else 
		{
			return true;
		}
	}
 
	public void setValueAt(Object aValue, int rows, int cols)
	{
		Zahlen[rows][cols] = aValue;
	 fireTableCellUpdated(rows, cols);
	 }
 
	public void fireTableCellUpdated(int row, int column) 
	{
	 fireTableChanged(new TableModelEvent(this, row, row, column));
	}
 
public void tableChanged(TableModelEvent e) 
{
int row = e.getFirstRow();
	 int column = e.getColumn();
	 tableModelM = (DefaultTableModel)e.getSource();
	 String columnName = tableModelM.getColumnName(column);
	 Object data = tableModelM.getValueAt(row, column);
 
}
 
 
public static void main(String[] args) 
{
 
	 FrameTable frame = new FrameTable();
	 frame.setLocation(150, 90);
	 frame.setSize(600,500);
	 frame.setResizable(true);
	 frame.setVisible(true);
}
 
 
 
 
 
 
	public void actionPerformed(ActionEvent e)
	{
 
	if (e.getActionCommand().equals("2")) 
	{ 
	 System.out.println(getValueAt(1, 1)); 
//setValueAt(new Integer(2), 1, 1) ;
 
	}
 
	if( e.getActionCommand().equals("4") )
	{
 
	 setValueAt(new Integer(4), 2, 2) ;
	}
 
	if( e.getActionCommand().equals("6") )
	{
	 setValueAt(new Integer(6), 2, 6) ;
	}
 
	if( e.getActionCommand().equals("8") )
	{
	 setValueAt(new Integer(8), 1, 8) ;
	}
 
	}
 
 
}
 
a400 hat gesagt.:
Desweiteren bekomme ich bei dieser Methode eine Fehlermeldung ohne Lösungstipp:

public void fireTableCellUpdated(int row, int column)
{
fireTableChanged(new TableModelEvent(this, row, row, column));
}

Jede Fehlermeldung beinhaltet eigentlich schon einen Tipp zur Beseitigung.

Ich hab jetzt schon an allem herumgetrickst, aber finde keine Lösungsmöglichkeit, dass das JTable hier die Zahl, die auf Knopfdruck gesetzt werden soll auch setzt, bzw im JTable dann auch anzeigt. Kann mir jemand dabei helfen, das hinzubekommen, oder sich zumnidest mal meinen Code anschauen und einfügen was ich ändern muss bzw. Tipps geben was daran falsch ist. Danke

Du hast die Tabellen noch nicht verstanden. Ich habe Dir unten minimalisierten, funktionierenden Code hingelegt. Die ganzen Methoden des TableModel (getValueAt, isCellEditable usw.) gehören doch nicht in diese Hauptklasse. Vor allem nicht, wenn sie nicht benötigt/benutzt werden. Ich konnte sie alle löschen. Weiterhin ist das eigentliche Problem der gleichen Art. Schau mal, worauf Du das setValueAt aufrufst. Das ist auf dem TableModel aufzurufen, nirgendwoanders.

Code:
/*
 * Created on 21.03.2005
 */

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class FrameTable extends JFrame implements ActionListener
{
  private class MeinWindowListener extends WindowAdapter
  {

    public void windowClosing(WindowEvent arg0)
    {
      System.exit(0);
    }
  }

  private String[]          columnNamen = { "Möglichkeit 1", "Möglichkeit 2",
      "Möglichkeit 3", "Möglichkeit 4" };

  private Object[][]        Zahlen      = {
      { new Integer(12), new Integer(2), new Integer(4), new Integer(6)

      }, { new Integer(12), new Integer(4), new Integer(13), new Integer(9)

      }, { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) },
      { new Integer(0), new Integer(0), new Integer(0), new Integer(0) } };

  private DefaultTableModel tableModelM;

  private JButton           b1, b2, b3, b4;

  private JComponent        jc          = (JComponent) getContentPane();

  FrameTable()
  {
    super();
    setTitle("FrameTable");
    setSize(800, 600);
    initLayout();
    setLocationRelativeTo(null);
    addWindowListener(new MeinWindowListener());
    setVisible(true);
    setResizable(true);
  }

  void initLayout()
  {
    jc.setLayout(new BorderLayout());

    // JTable erstellen
    tableModelM = new DefaultTableModel(Zahlen, columnNamen);

    JTable tableZahlen = new JTable(tableModelM);
    tableZahlen.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);

    // tableSpieler einem Container zuführen
    JScrollPane scrollM = new JScrollPane(tableZahlen);
    scrollM.setPreferredSize(new Dimension(300, 300));

    // West
    JPanel wPnl = new JPanel();
    wPnl.add("Center", scrollM);
    jc.add("West", wPnl);

    // South
    JButton b1 = new JButton("2");
    b1.addActionListener(this);
    JButton b2 = new JButton("4");
    b2.addActionListener(this);
    JButton b3 = new JButton("6");
    b3.addActionListener(this);
    JButton b4 = new JButton("8");
    b4.addActionListener(this);

    JPanel sPnl = new JPanel();
    sPnl.add(b1);
    sPnl.add(b2);
    sPnl.add(b3);
    sPnl.add(b4);
    jc.add("South", sPnl);
  }

  public static void main(String[] args)
  {
    FrameTable frame = new FrameTable();
    frame.setLocation(150, 90);
    frame.setSize(600, 500);
    frame.setResizable(true);
    frame.setVisible(true);
  }

  public void actionPerformed(ActionEvent e)
  {

    if (e.getActionCommand().equals("2"))
    {
      tableModelM.setValueAt(new Integer(2), 1, 1);
    }

    if (e.getActionCommand().equals("4"))
    {

      tableModelM.setValueAt(new Integer(4), 2, 2);
    }

    if (e.getActionCommand().equals("6"))
    {
      tableModelM.setValueAt(new Integer(6), 6, 2);
    }

    if (e.getActionCommand().equals("8"))
    {
      tableModelM.setValueAt(new Integer(8), 8, 1);
    }
  }
}
 
Okay, danke Snape ich werd mir nochmal das Kapitel JTable etwas fundierter anschauen, damit ich nicht wieder so eine Frage stellen muss, vielen Dank trotzdem.
 
Wichtig ist zu verstehen, wie Tabelle, TableModel, Renderer, Editoren, TableColumns und TableHeader zusammen spielen. Ein aufschlussreiches Schaubild darüber gibt es in dem Buch "Java Swing" von O'Reilly.
 
Bin ich wirklich sooo dumm Hier ist mein Beispiel, einfach in TickTest.java kopieren und kompilieren. Ich verstehe beim besten Willen nicht, warum die Tabelle nicht geupdatet wird nach einem Aufruf von setValueAt(). Wäre wirklich sehr dankbar, wenn mir jemand die Ursache für die Brummschleife in meinem Schädel nennen könnte... beachtet bitte die Kommentare im Code.

Gruß,

Roman

Code:
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;

public class TickTest{
	
	public static void main(String[] args){

		SumTableModel m = new SumTableModel(3);

		m.setValueAt("a",0,0);
		m.setValueAt("b",0,1);
		m.setValueAt("c",0,2);

		JTable SumTable = new JTable(m);
		
		System.out.println(SumTable.getModel() == m); //Liefert true
		
		// Warum funktioniert dann:
		m.setValueAt("Doof",0,0);
		
		// ... aber nicht:
		SumTable.getModel().setValueAt("Saudoof",0,0);
		
		// Die Methode hier würde idealerweise funktionieren, denn falls der Nutzer die Reihenfolge der Columns mit der Maus verschiebt, bleibt die Position im Model gleich! Und in meinem Fall müsste ich dann erstmal rumsuchen, welche Zeile im View gerade welche Zeile im Model repräsentiert.
		SumTable.setValueAt("Dum-di-dum",0,0); //Does not work. Why!?

		//Der ganze Kram hier hat keinerlei Auswirkungen:
		((AbstractTableModel)(SumTable.getModel())).fireTableDataChanged(); //Funktioniert auch nicht :(
		SumTable.revalidate();
		SumTable.repaint();

		//SumTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION); //Eigentlich will ich, dass gar keine Zellen auswählbar sind.
		SumTable.setSelectionBackground(Color.white);
		
		JScrollPane p = new JScrollPane(SumTable);

		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setSize(400,300);
		frame.getContentPane().add(p);
		frame.setVisible(true);

		/*
		 * Später Update-Funktion: Falls sich an der Main-Table was ändert, muss die SumTable neu berechnet werden!
		 *
		 * Moment mal: Eigentlich brauch ich SumTable gar nicht, sondern das SumTableModel kommt mit der Main-Table in eine einzige JTable rein.
		 */
	}
}

class SumTableModel extends AbstractTableModel{
	
			private String[][] data;
			private String[] headers;
	
			public SumTableModel(int c){
				data = new String[1][ c];
				headers = new String[ c];
			}
			
			public int getRowCount(){ return 1; }

			public int getColumnCount(){ return data[0].length; }
			
			public Object getValueAt(int r, int c){ return data[r][ c]; }

			public Object getValueAt(int c){ return data[0][ c];	}

			public String getColumnName(int c){ return headers[ c]; }
			
			public void setValueAt(String s, int r, int c){
				data[r][ c] = s;
				//fireTableCellUpdated(r,c);
				//fireTableDataChanged(); It all doesn't work How can I update the table's view!
			}
			
			public void setValueAt(String s, int c){
				data[0][ c] = s;
			}
			
			public void setColumnName(String s, int c){
				headers[ c] = s;
			}
}
 
Ach so, um eine Frage gleich vorweg zu beantworten: Warum mache ich es nicht über 'm'? Weil ich da später nur noch über die getModel()-Methode rankomme, weil ich im Hauptprogramm nur noch eine Referenz auf die JTable haben werde. Desh. würde bestenfalls die set-Methode direkt auf der Table funktioniern....
 
equestenebrarum hat gesagt.:
// Warum funktioniert dann:
m.setValueAt("Doof",0,0);

// ... aber nicht:
SumTable.getModel().setValueAt("Saudoof",0,0);

Preisfrage:
Was bekommst Du mit

Code:
SumTable.getModel()

?
.
.
.
.
.
.
.
.
.
.
.
.
Laut API:
public TableModel getModel()

Du hast aber ein SubTableModel, also was meinst Du, wie es funktioniert?
.
.
.
.
.
.
.
.
.
.
.
.
.
.
((SumTableModel)SumTable.getModel()).setValueAt("Saudoof", 0, 0);
 
Hi, die Antwort auf die Preisfrage lautet:

((SumTableModel)(SumTable.getModel())).setValueAt("Saudoof",0,0);

Vielen Dank für die schnelle Hilfe. Ohne Dich hätte ich wohl noch ewig gesucht...
 
Und was war der Preis? ;)

Du scheinst Dich ja wirklich super mit Tabellen auszukennen. Da hab ich gleich noch eine Frage... ich möchte die Zellen in einer großen Tabelle alle einzeln einfärben, abhängig vom Wert, den sie zu einem fixen Zeitpunkt enthalten. Folgendes funktioniert nicht wie erwartet.

JTable SumTable = new JTable(m);

TableCellRenderer cr = SumTable.getCellRenderer(0,0);
((DefaultTableCellRenderer)cr).setBackground(Color.red);

cr = SumTable.getCellRenderer(0,1);
((DefaultTableCellRenderer)cr).setBackground(Color.green);

Muss ich für jede einzelne Zelle ein eigenes cell-Renderer-Object erstellen? Dann ist der Overhead wohl so groß, dass die Lösung nicht sooo sinnvoll ist. Fällt Dir da eine elegantere Lösung ein?

In meinem Beispiel ist es übrigens so, dass die Zellenwerte Integer-Werte repräsentieren und mit verschiedenen Grüntönen deren Größe wiedergespiegelt werden soll.
 

Neue Beiträge

Zurück