# JTable - warum funktioniert mein CellRenderer nicht?



## Kiamur (26. Apr 2006)

Hallo!

Ich möchte in meiner Tabelle den Text der darzustellenden Strings in unterschiedlichen Farben darstellen.

Dazu habe ich mir eine Cell Renderer geschrieben, der so aussieht:


```
public class MyCellRenderer extends JLabel implements TableCellRenderer
{

	
	public MyCellRenderer()
	{
		setOpaque(true);
	}

	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
	{
		setForeground(Color.RED);
		
		return this;
	}

}
```

Ich habe mich dabei am Tutorial hier im Forum orientiert.

Ich habe auch ein eigenes TableModel geschrieben, das so aussieht:


```
public class MyTableModel extends DefaultTableModel
{
	public MyTableModel(int size, int i)
	{
		super(size, i);
	}

	// make all cells NOT editable
	public boolean isCellEditable(int rowIndex, int ColumnIndex)
	{
		return false;
	}
}
```

Den CellRenderer habe ich dann so meiner Tabelleninstanz übergeben:


```
table.setDefaultRenderer(String.class, new MyCellRenderer());
```

Leider wird der Text in der Tabelle nicht rot dargestellt, sondern immer noch schwarz. Auch konnte ich so nicht die Hintergrundfarbe der Zellen ändern. Es tut sich einfach gar nichts. Könnt ihr mir sagen, was ich noch falsch mache?

Gruß
Maik


----------



## André Uhres (26. Apr 2006)

Kiamur hat gesagt.:
			
		

> ...
> 
> 
> 
> ...


Versuch's mal so:

```
table.setDefaultRenderer(Object.class, new MyCellRenderer());
```


----------



## Kremso (27. Apr 2006)

Falls Andrés Vorschlag nicht funzt, versuchs mal mit

```
table.getColumnModel().getColumn(index).setCellRenderer(new MyCellRenderer());
```


----------



## Kiamur (27. Apr 2006)

Hallo ihr zwei!

Danke erst mal für eure Antworten. Leider funktioniert es immer noch nicht.

In der Version von André werden keine Strings mehr in die Tablle geschrieben. Es erscheint die Tabelle mit der richtigen Anzahl von Zeilen und Spalten, aber die Zellen sind grau und es steht nichts drin (das Grau kommt aber nicht von meinem CellRenderer).

In der Version von Kremso werden zwar alle Werte in die Tabelle geschrieben, aber nicht rot. Außerdem sieht die letzte Spalte genauso aus wie in der Version von André (also grau). Nur das da noch nichts drin steht ist richtig.

Der Code, wo ich Kremsos Vorschlag eingebaut habe sieht so aus: (ich denke André wird das bekannt vorkommen)


```
// adds a new column to the table
	public static void addNewColumn()
	{
		// add a new Column to the table
    	model.addColumn(model.getColumnCount()+1);
    	
    	// autoscroll the scrollbar to the last column
    	SwingUtilities.invokeLater(new Runnable()
    	{
    		public void run()
    		{
    			table.changeSelection(table.getSelectedRow(), table.getColumnCount(), false, false);
    			table.getColumnModel().getColumn(model.getColumnCount()-1).setCellRenderer(new MyCellRenderer());
    		}
    	});
	}
```

Was ich überhaupt nicht verstehe, das ist, dass die Tabelle ja Reaktionen auf den CellRenderer zeigt, wenn ich ihn einfüge. Aber leider sind es nicht die Reaktionen, die ich dort hineinprogrammiert habe:


```
setForeground(Color.RED);
```

Bitte helft mir weiter, denn ich brauche die Farben in der Tabelle.

Gruß
Maik


----------



## André Uhres (27. Apr 2006)

```
/*
 * CellRendering2.java
 */
//package tableDemo;
import java.awt.*;
import javax.swing.*;
import javax.swing.table.*;
public class CellRendering2 extends JFrame {
    public CellRendering2() {
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setSize(400,300);
        setLocationRelativeTo(null);
        JTable table = new JTable(new MyTableModel(100,4));
        table.setDefaultRenderer(Object.class, new MyCellRenderer());
        add(new JScrollPane(table));
    }
    public static void main(String args[]) {new CellRendering2().setVisible(true);}
    public class MyCellRenderer extends JLabel implements TableCellRenderer {
        public MyCellRenderer() {
            setOpaque(true);
        }
        public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
            setBackground(Color.RED);
            return this;
        }
    }
    public class MyTableModel extends DefaultTableModel {
        public MyTableModel(int size, int i) {
            super(size, i);
        }
        // make all cells NOT editable
        public boolean isCellEditable(int rowIndex, int ColumnIndex) {
            return false;
        }
    }
}
```


----------



## Kiamur (28. Apr 2006)

Hallo André!

Tja, so funktioniert das Ganze ja wunderbar, nur warum nicht in meinem Programm?

Interessant ist, dass ich in deiner Version den MyCellRenderer auch debuggen kann. D.h., wenn ich darin Haltepunkte setze, dann stoppt der Debugger auch dort. In meinem Programm kommt der Debugger nie in meinem CellRenderer "vorbei".

Das verstehe ich nicht, denn ich übergebe ihr doch auf die gleiche Art und Weise wie du. 

Hier ist mal der komplette Code meines TableControllers, der die Tabellen erstellt und verwaltet. Vielleicht findest du (oder ihr) ja den Fehler, den ich gemacht habe. Ich hoffe ihr steigt da durch.


```
// This class creates and administrates the tables and tablepanels showing the 
// measurement values of a serie.
public class TableController
{
	private static MyTablePanel tablePanel = new MyTablePanel();
	private static MyJTable table; 
	private static Vector rowStrings = new Vector(); 
	private static MyTableModel model;
	
	private static boolean keyPressed = false;
	
	// returns the actual tablepanel object
	public static MyTablePanel returnTablePanel()
	{
		return tablePanel;
	}
	
	// creates new table object dependent on the count of sensors
	@SuppressWarnings("unchecked")
	public static void createNewTable(int rows) throws Exception
	{
		rowStrings.clear();
		
		for(int i = 0; i < rows; i++)
		{
			String s = new String("Sensor ");
			s += i+1;
			rowStrings.add(s);
		}
		
		ListModel listModel = new AbstractListModel()
        {
            /**
			 * 
			 */
			private static final long serialVersionUID = 1L;
			
			public int getSize()
            {
            	return rowStrings.size();
            }
            public Object getElementAt(int index)
            {
            	return rowStrings.get(index);
            }
        };
        
        model = new MyTableModel(listModel.getSize(), 0);
        
        // look if there ist allready data in this serie
        int sdc = WorkingSet.getActualSerieDataCount();
        int sc = WorkingSet.getActualSensors();
        for(int i = 0; i < sdc; i++)
        {
        	addNewColumn();
        	for(int j = 0; j < sc; j++)
        	{
        		String s = String.valueOf(WorkingSet.getCertainValue(i, j));
        		model.setValueAt(s, j, i);
        	}
        }
        
        // add at least 1 column to the table, or at the end of it.
        addNewColumn();
		
        // create Table as desired
		table = null;
		table = new MyJTable(model);
		table.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		table.setRowSelectionAllowed(false);
		table.setColumnSelectionAllowed(true);
		table.getTableHeader().setReorderingAllowed(false);
		table.setDefaultRenderer(String.class, new MyCellRenderer());
		
		// implement tooltips into the tabel
		ToolTipManager.sharedInstance().registerComponent(table);
		ToolTipManager.sharedInstance().setDismissDelay(10000);
		ToolTipManager.sharedInstance().setEnabled(true);
		
		// set the custom MouseListener class as the tables mouse listener
		table.addMouseListener(new MyTableMouseListener());		
		
		// create the row header
		JList rowHeader = new JList(listModel);
		rowHeader.setBackground(tablePanel.getBackground());
        rowHeader.setFixedCellWidth(50);
        rowHeader.setFixedCellHeight(table.getRowHeight());
        rowHeader.setCellRenderer(new RowHeaderRenderer(table));
        
        tablePanel.getScrollPane().setViewportView(table);
        tablePanel.getScrollPane().setRowHeaderView(rowHeader);
	}
	
	// adds a new column to the table
	public static void addNewColumn()
	{
		// add a new Column to the table
    	model.addColumn(model.getColumnCount()+1);
    	
    	// autoscroll the scrollbar to the last column
    	SwingUtilities.invokeLater(new Runnable()
    	{
    		public void run()
    		{
    			table.changeSelection(table.getSelectedRow(), table.getColumnCount(), false, false);
    			table.getColumnModel().getColumn(model.getColumnCount()-1).setCellRenderer(new MyCellRenderer());
    		}
    	});
	}
	
	// adds measurement values to a column
	public static void fillInValue(int row, double diffValue)
	{
		String s = String.valueOf(diffValue);
		int column = model.getColumnCount();
		table.setValueAt(s, row-1, column-1);
	}

	public static boolean isKeyPressed()
	{
		return keyPressed;
	}

	public static void setKeyPressed(boolean keyPressed)
	{
		TableController.keyPressed = keyPressed;
	}
}
```

Gruß
Maik


----------



## André Uhres (29. Apr 2006)

Kiamur hat gesagt.:
			
		

> ...Ich hoffe ihr steigt da durch....


Sry, ich leider nicht.
Aber vielleicht kannst du mal überprüfen ob irgendeine Fehlermeldung 
auf der Java Console erscheint.


----------



## Kiamur (29. Apr 2006)

Hallo André!

Hmmm, so kompliziert ist die Klasse doch auch nicht, oder?

Naja, auf der Konsole kommt keine Fehlermeldung.

Das mit dem Debugger muss ich noch mal relativieren. Wenn ich einen Haltepunkt im Konstruktor setze, dann wird dieser bei der Ausführung auch erreicht. Das heisst ja dann wohl, dass der CellRenderer der Tabelle zugeordnet wurde. Aber es wird einfach nie die Methode "getTableCellRendererComponent()"  aufgerufen, die ja letztendlich für das Zeichnen der Zelleninhalte zuständig ist. 

Unter welchen Umständen wird diese Methode denn nun genau aufgerufen?!? Ich dachte eigentlich immer dann, wenn etwas in die Tabelle mit z.B. "setValueAt()" eingefügt wird. Der Wert, der dann in die Tabelle soll wird doch dann dem CellRenderer übergeben, und dieser entscheidet dann, wie der Wert dargestellt wird. Oder bin ich da auf dem Holzweg?!?
Aber wie kann es dann sein, dass der CellRenderer zwar der Tabelle richtig zugeordnet ist, auber nicht die Methode "getTableCellRendererComponent()" aufgerufen wird, wenn ich etwas in die Tabelle wie eben beschrieben hineinschreibe?!?

Gibt es irgendetwas, womit ich den Aufruf der Methode "getTableCellRendererComponent()" sicher provoziere?

Gruß
Maik


----------



## André Uhres (29. Apr 2006)

Kiamur hat gesagt.:
			
		

> ...Gibt es irgendetwas, womit ich den Aufruf der Methode "getTableCellRendererComponent()" sicher provoziere?...


Das müsste die JTable API automatisch regeln.
Für mich ist dein Code ehrlich gesagt zu kompliziert, ich blicke da kaum durch.

Ich schlage vor du machst dir erstmal ein einfaches Beispiel das funktioniert. 
Davon gehst du dann aus um es schrittweise zu erweitern. Wenn dann ein Problem kommt,
dann weisst du genau dass es durch die letzte Erweiterung bedingt ist und brauchst nicht stundenlang
oder tagelang nach der Ursache zu suchen.

Das mag vielleicht jetzt übertrieben klingen. 
Dennoch glaube ich, daß es der schnellste Weg zur Lösung ist.


----------



## Kiamur (30. Apr 2006)

Hallo!

Nach einer langen Nacht habe ich es jetzt hinbekommen. Das komische ist, dass ich nicht so genau weiss, wo mein Fehler nun eigentlich war. Ich denke mal es lag an meinem Unwissen, was diese CellRenderer Thematik betrifft.

Wenn man so einen CellRenderer schreibt, dann muss man ihm ja wirklich ALLES mit auf den Weg geben, was er machen soll. Wenn man gar nichts reinschreibt, dann ergibt sich genau der Effekt, den ich weiter oben beschrieben habe. Nämlich, dass alle Zellen grau sind und nichts drin steht. Mein CellRenderer sieht jetzt so aus und macht seine Arbeit auch ganz gut:


```
// custom cell renderer makes the overstepping of the tolerance visible
public class MyCellRenderer extends JLabel implements TableCellRenderer
{
	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	public MyCellRenderer()
	{
		setOpaque(true);
	}

	public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
	{
		// set the default color for a cell
		setForeground(Color.BLACK);
		setBackground(Color.WHITE);
		
		if(value instanceof String)
		{
			if(value.toString().equals(" "))
			{
				setText(" ");
				return this;
			}				
			
			// determine if the cells value is out of tolerance
			double d = Double.parseDouble(value.toString());
			double t = WorkingSet.getActualTolerance();
			
			if((d > t) || (d < t*-1))
				setForeground(Color.RED);
			
			setText(value.toString());
			
			if(isSelected)
				setBackground(Color.BLUE);
		}
		
		return this;
	}
}
```

Allerdings habe ich jetzt wieder ein Problem, doch dafür mache ich dann mal einen neuen Thread auf.

Gruß 
Maik

. . . und Sorry für meine lange Leitung . . .


----------

