TableCellRenderer UND prepareRenderer

UnkiDunki

Bekanntes Mitglied
Hi,

ich habe eine Frage zum Gebrauch des TableCellRenderers:

Ist es möglich gleichzeitig mit einer Table-Klasse zu arbeiten, worin ich die prepareRenderer-Methode überschrieben habe und an anderer Stelle mit setDefaultRenderer einen TableCellRenderer setzen möchte und beides sozusagen in Kombination funktioniert... Wahrscheinlich stehe ich da auf dem Schlauch, wie dieses genau vorzunehmen ist...
 

André Uhres

Top Contributor
Ein Renderer ist immer notwendig. Wenn man keinen eigenen setzt, wird ein Standardrenderer eingesetzt.
Unabhängig davon kann die Methode prepareRenderer immer zusätzlich benutzt werden. Wie der Name andeutet, wird er dem Renderer vorgelagert um allgemeinere Darstellungen umzusetzen, wie z.B. Zeilen einzufärben oder einen speziellen Rand um die ausgewählte Zeile zu malen.
 

UnkiDunki

Bekanntes Mitglied
Hi,

danke für die Erklärung. Das Problem ist und auch der Grund, warum ich hier poste: Bei mir spielt beides nicht zusammen. So, wie ich das hier sehe, wird nur der Code im überschriebenen prepareRenderer() umgesetzt, aber irgendwie nicht das, was ich hinterher in einem eigenen Renderer, den ich mit setDefaultRenderer() setze, realisiert haben möchte.

Kann das sein oder liegt der Fehler dann woanders, denn nach deiner Erklärung müsste das ganze ja dann zusammenspielen können...

Nachfrage: Als ersten Parameter möchte setDefaultRenderer ja eine Klasse haben, z.B. Double.class. Bedeutet das dann, dass er nur die Zellen von diesem Typ entsprechend formatiert? Und wenn man dieses allgemein halten will, wie müsste was müsste man dann übergeben oder macht das ganze dann keinen Sinn?
 
Zuletzt bearbeitet:

André Uhres

Top Contributor
Ein Renderer gilt für eine Spalte oder für einen Datentyp (gemäß "getColumnClass" im "TableModel"). Die Methode "prepareRenderer" wird für zeilen- oder tabellenabhängige Erfordernisse genutzt. Sie kann keine Renderer ausschalten sondern nur "vorbereiten".
Wenn du noch Hilfe brauchst, mach bitte ein kurzes, selbständiges und kompilierbares Beispiel.
 

UnkiDunki

Bekanntes Mitglied
Hi André,

Deine Erklärungen und dein Hilfsangebot weiss ich sehr zu schätzen :)
Ich habe jetzt mal den Renderer aus der FAQ http://www.java-forum.org/java-faq-beitraege/7032-jtable-teil-4-darstellung-daten.html (Punkt 3) übernommen und konnte das Problem jetzt eingrenzen. Die Zellen werden alle ordnungsgemäß gerendert, was aber NICHT funktioniert, ist der Farbwechsel beim Selektieren einer Zeile/Zelle...

Das Problem ist das Zusammenspiel zwischen diesem beschrieben Farbwechsel
Java:
// die normalen Farben
        setForeground( Color.BLACK );
        if( hasFocus )
            setBackground( colorFocus );
        else if( isSelected )
            setBackground( colorSelected );
        else
            setBackground( colorNormal );
und einer voher getätigten Einfärben der Zeilen/Zellen abhängig von deren Inhalten. Vielleicht erinnerst du dich, denn auch dabei hast du mir geholfen:

Java:
 public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
	        Component c = super.prepareRenderer(renderer, row, column);
	        int rowM = convertRowIndexToModel(row);
	        int red = Integer.valueOf(this.getModel().getValueAt(rowM, RED).toString());
	        int green = Integer.valueOf(this.getModel().getValueAt(rowM, GREEN).toString());
	        int blue = Integer.valueOf(this.getModel().getValueAt(rowM, BLUE).toString());
	        c.setBackground(new Color(red, green, blue));
	        return c;
	    }

Ich könnte mir jetzt erklären, warum eine Zelle/Zeile nicht ihre ursprüngliche Farbe zurückerhält, wenn sie den Focus verliert bzw. nicht mehr ausgewählt ist, aber warum sie bei ihrer Selektierung anfänglich nicht wenigstens mit den Farben colorFocus oder colorSelected eingefärbt wird nicht...

Problem 1: Warum ändert sich die Farbe bei Selektion nicht?
Problem 2: colorNormal ist ja bei jeder Zelle/Zeile verschieden, wie erreicht man bei z.B. Verlust des Focuses eine Zurücksetzung auf diese?
Wäre das schon mit einem anfänglichen
Java:
colorNormal = getBackground();
getan? Ausprobieren kann ich es ja leider noch nicht, da die grundsätzliche Selektionseinfärbung nicht funktioniert...

Vielen Dank im Voraus für Anregungen :)
 

Michael...

Top Contributor
Hast mal ein KSKB zu dem was Du vorhast?
Da Du nach in der überschriebenen prepareRenderer() nach dem Aufruf von super.prepareRenderer() in Zeile 7 die Hintergrundfarbe setzt, müsste das Setzen des Hintergrunds im DefaultCellRenderer "ignoriert" werden.
 

UnkiDunki

Bekanntes Mitglied
Hi,

gerne mache ich dir ein KSKB. Hoffe, es läuft :) LG

P.S.: Die Zeile wird gemäß den drei Integerwerten in Columns 4,5 und 6 grün eingefärbt und auch z.B. der Booleanwerte gemäß dem Renderer in einen String verändert. Eine merkliche (Farbveränderung) Zeilenauswahl tut sich aber leider nicht...

Java:
package main;
import java.awt.Color;
import java.awt.Component;
import java.util.Date;

import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class KSKB{

   public static void main( String[] args ){
      // Unser TableModel (siehe unten)
     KSKBTableModel model = new KSKBTableModel();
      Object[] objects = new Object[]{"Text",Float.valueOf( 5.123f ),true,new Date( System.currentTimeMillis() ),110,210,98};
      model.addRow(objects);

      // Das JTable initialisieren
      MyColoredJTable table = new MyColoredJTable();
      table.setDefaultRenderer(Object.class, new CellRenderer());
      table.setModel(model);

      JFrame frame = new JFrame( "Demo" );
      frame.getContentPane().add( new JScrollPane( table ) );

      frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
      frame.pack();
      frame.setVisible( true );
   }
}

class KSKBTableModel extends DefaultTableModel {

	private static final long serialVersionUID = 1L;

	public KSKBTableModel(){
		super();
		setColumnIdentifiers(new String[]{"String","Float","Boolean","Date","ColorR", "ColorG", "ColorB"});
	}

	@SuppressWarnings("unchecked")
	public Class getColumnClass(int columnIndex) {

		switch (columnIndex) {
		case 0:
			return String.class;
		case 1:
			return Float.class;
		case 2:
			return String.class;
		case 3:
			return Date.class;
		case 4:
			return Integer.class;
		case 5:
			return Integer.class;
		case 6:
			return Integer.class;
		default:
			return null;
		}
	}
}

class CellRenderer extends JLabel implements TableCellRenderer {

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;

	private Color colorSelected = new Color( 200, 255, 200 );
    private Color colorFocus = new Color( 255, 200, 200 );
    private Color colorNormal = new Color( 200, 200, 255 );

	public CellRenderer() {
		setOpaque(true);
	}

	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		// TODO Auto-generated method stub

		colorNormal = getBackground();
		 // die normalen Farben
        setForeground( Color.BLACK );
        if( hasFocus )
            setBackground( colorFocus );
        else if( isSelected )
            setBackground( colorSelected );
        else
            setBackground( colorNormal );

        setText( null );
        setIcon( null );

        if( value instanceof Date )
            setText( ((Date)value).toGMTString() );
        else if( value instanceof Icon )
            setIcon( (Icon)value );
        else if( value instanceof Color ){
            Color color = (Color)value;
            setForeground( color );
            setText( color.getRed() + ", " + color.getGreen() + ", " + color.getBlue() );
        }
        else if( value instanceof Boolean ){
            if( ((Boolean)value).booleanValue() )
                setText( "yes" );
            else
                setText( "no" );
        }
        else if(value != null)
            setText( value.toString() );

        return this;
	}
}

class MyColoredJTable extends JTable {

	/**
	 *
	 */
	private static final long serialVersionUID = 1L;
	private int RED = 4;	//column index of the red color part
    private int GREEN = 5;	//column index of the green color part
    private int BLUE = 6;	//column index of the blue color part

	public MyColoredJTable() {
		// TODO Auto-generated constructor stub
	}

	public MyColoredJTable(DefaultTableModel tableModel) {
		super(tableModel);
		// TODO Auto-generated constructor stub
	}

	@Override
	    public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
	        Component c = super.prepareRenderer(renderer, row, column);
	        int rowM = convertRowIndexToModel(row);
	        int red = Integer.valueOf(this.getModel().getValueAt(rowM, RED).toString());
	        int green = Integer.valueOf(this.getModel().getValueAt(rowM, GREEN).toString());
	        int blue = Integer.valueOf(this.getModel().getValueAt(rowM, BLUE).toString());
	        c.setBackground(new Color(red, green, blue));
	        return c;
	    }
}
 
Zuletzt bearbeitet:

Michael...

Top Contributor
Naja, durch die überschriebene prepareRenderer() machst Du ja jede im CellRenderer gesetzte Hintergrundfarbe zu nichte.

Worum geht's Dir genau? Willst Du nur, dass man die Selektion in der Zeile erkennt (soll die Standardselektion verwendet werden) und die anderen Zeilen entsprechend der drei in den letzten drei Spalten eingefärbt werden?
 

UnkiDunki

Bekanntes Mitglied
Worum geht's Dir genau? Willst Du nur, dass man die Selektion in der Zeile erkennt (soll die Standardselektion verwendet werden) und die anderen Zeilen entsprechend der drei in den letzten drei Spalten eingefärbt werden?

Genau. Eine Selektion einer Zeile soll erkennbar sein und grundsätzlich alle Zeilen standardmäßig mit ihren RGB-Werten aus den drei letzten Spalten eingefärbt sein und diese Farbe bei Nicht-Selektion wieder annehmen.
 

Michael...

Top Contributor
Probier mal ob folgendes Dein Problem löst. Funktioniert allerdings noch nicht bei Selektion mehrerer Zeilen und ich habe in der prepareRenderer die Zeilenkonvertierung (Zeile 51)
Code:
int rowM = convertRowIndexToModel(row);
raus gemacht, da diese Methode erst ab 1.6 zur Verfügung steht und ich hier max 1.5 habe.

Java:
import java.awt.Color;
import java.awt.Component;
import java.text.DateFormat;
import java.util.Date;

import javax.swing.Icon;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class KSKB {

	private static int RED = 4; // column index of the red color part
	private static int GREEN = 5; // column index of the green color part
	private static int BLUE = 6; // column index of the blue color part
	private static JTable table;

	public static void main(String[] args) {
		DefaultTableModel model = new DefaultTableModel(new Object[][] {
				{ "Text", 5.123f, true, new Date(System.currentTimeMillis()), 110, 210, 98 },
				{ "Text", 4.123f, true, new Date(System.currentTimeMillis()), 110, 200, 200 } }, 
				new String[] { "String", "Float", "Boolean", "Date", "ColorR", "ColorG", "ColorB" }) {
			public Class getColumnClass(int columnIndex) {
				switch (columnIndex) {
				case 0:
					return String.class;
				case 1:
					return Float.class;
				case 2:
					return String.class;
				case 3:
					return Date.class;
				case 4:
				case 5:
				case 6:
					return Integer.class;
				default:
					return null;
				}
			}
		};
		table = new JTable(model) {
			public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
				Component c = super.prepareRenderer(renderer, row, column);
				if (table.getSelectedRow()==row)
					return c;
				
				int rowM = row;
				int red = Integer.valueOf(this.getModel().getValueAt(rowM, RED).toString());
				int green = Integer.valueOf(this.getModel().getValueAt(rowM, GREEN).toString());
				int blue = Integer.valueOf(this.getModel().getValueAt(rowM,	BLUE).toString());
				c.setBackground(new Color(red, green, blue));
				return c;
			} 
		};
		table.getSelectedRows();
		table.setDefaultRenderer(Object.class, new CellRenderer());

		JFrame frame = new JFrame("Demo");
		frame.getContentPane().add(new JScrollPane(table));
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.pack();
		frame.setVisible(true);
	}
}

class CellRenderer extends DefaultTableCellRenderer {

	public Component getTableCellRendererComponent(JTable table, Object value,
			boolean isSelected, boolean hasFocus, int row, int column) {
		super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
		
		if (value instanceof Date)
			setText(DateFormat.getDateInstance().format((Date) value));
		else if (value instanceof Icon)
			setIcon((Icon) value);
		else if (value instanceof Boolean) {
			if (((Boolean) value).booleanValue())
				setText("yes");
			else
				setText("no");
		}
		return this;
	}
}
 

UnkiDunki

Bekanntes Mitglied
Hi Michael...

danke erstmal für das schöne Formatieren meines KSKBs. Gib zu, dass das sowas wie ein Putzfimmel ist ;)
Das Geheimnis ist also folgende Zeile
Java:
if (getSelectedRow()==row) return c;
Da wäre ich nicht drauf gekommen...
Und ja, schade, dass es bei Multiselektion nicht funktioniert, aber schon mal nicht schlecht! Vielen Dank :)
 

Michael...

Top Contributor
Hatte gestern ein bisschen Frust und da kam mir halt Dein Code in die Finger ;-)

Man kann das ja durchaus erweitern, damit das auch mit der Multiselektion funktionert. Es gibt ja auch noch sowas wie getSelectedRows() usw. Eventuell gibt's ja noch eine bessere Möglichkeit.
 

UnkiDunki

Bekanntes Mitglied
Hi,

ok, stimmt, bei getSelectedRows() werde ich noch mal ansetzen. Das ist ja auch noch da :)

Noch mal ne allgemeinere Frage:
Ich habe jetzt einen TableCellRenderer im Einsatz, der sich um alle Objekte kümmern soll. Die Frage ist jetzt woher er weiss, von welcher Instanz die "value" ist? Das müsste doch vom TableModel kommen, oder nicht?
Ich frage deswegen, weil er anscheinend bei mir nur Booleans erkennt und rendert, aber bei z.B. BigDecimal, etc. irgendwie garnichts macht.
Wenn ich also z.B. BigDecimals rendern möchte, muss ich einen DefaultTableCellRenderer benutzen und dort die Methode setValue überschreiben. Wenn ich deren Inhalt aber im TableCellRender in die if-Abfrage value instanceof BigDecimal packe, tut sich garnichts...
Fakt ist, dass ich eigentlich nur für Booleans wirklich Anweisungen zum Rendern geben kann... Mhmm...
Wie kommt das?

Hat das vielleicht damit zu tun, wann ich den DefaultRenderer setze oder ist das egal? Also vor oder nachdem ich das TableModel (neu)setze.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
B TableCellRenderer rendert Integer/Boolean Felder nicht AWT, Swing, JavaFX & SWT 4
M Swing TableCellRenderer elegant anpassen AWT, Swing, JavaFX & SWT 3
D Swing Mit TableCellRenderer einzelne Zellen markieren AWT, Swing, JavaFX & SWT 3
O Swing TableCellRenderer und JComboBox AWT, Swing, JavaFX & SWT 4
C Swing TableCellRenderer: setText() vs. setIcon() AWT, Swing, JavaFX & SWT 5
E Swing TableCellRenderer für alle Splaten setzen?! AWT, Swing, JavaFX & SWT 3
M gleicher TableCellRenderer für mehrere unterschiedliche Tabellen AWT, Swing, JavaFX & SWT 5
A Swing TableCellRenderer ändert die Zeilenfarbe zu spät AWT, Swing, JavaFX & SWT 3
J Swing JTable, eigener TableCellRenderer Keine Anzeige in den Zellen AWT, Swing, JavaFX & SWT 8
J NullPointerException bei Benutzung vom TableCellRenderer AWT, Swing, JavaFX & SWT 3
U TableCellRenderer: Problem mit Timestamp/Date AWT, Swing, JavaFX & SWT 2
C Swing TableCellRenderer AWT, Swing, JavaFX & SWT 10
U TableCellRenderer und setBackground AWT, Swing, JavaFX & SWT 20
H Swing TableCellRenderer für verschiedene Spalten AWT, Swing, JavaFX & SWT 11
C Swing Problem mit TableCellRenderer in Verbindung mit TableRowSorter AWT, Swing, JavaFX & SWT 2
R JTable - TableCellRenderer AWT, Swing, JavaFX & SWT 3
R JTable - TableCellRenderer - BufferedImage AWT, Swing, JavaFX & SWT 9
S TableCellRenderer: JLabel-Background in JPanel AWT, Swing, JavaFX & SWT 7
R JTable mit TableCellRenderer AWT, Swing, JavaFX & SWT 10
R JTable - TableCellRenderer AWT, Swing, JavaFX & SWT 2
D TableCellRenderer rendert einfach nicht! AWT, Swing, JavaFX & SWT 4
S TableCellRenderer setForeground AWT, Swing, JavaFX & SWT 5
I Problem mit TableCellRenderer AWT, Swing, JavaFX & SWT 3
K TableCellRenderer Problem AWT, Swing, JavaFX & SWT 3
F TableCellRenderer wie umsetzen? AWT, Swing, JavaFX & SWT 2
D JTable TableCellRenderer AWT, Swing, JavaFX & SWT 2
J JTable und TableCellRenderer AWT, Swing, JavaFX & SWT 2
G TableCellRenderer Background variiert darstellen AWT, Swing, JavaFX & SWT 3
P TableCellRenderer mit einem TableRowSorter AWT, Swing, JavaFX & SWT 4
D TableCellRenderer PRoblem AWT, Swing, JavaFX & SWT 3
G TableCellRenderer soll ganze ausgewählte Zeile markieren AWT, Swing, JavaFX & SWT 2
S TableCellRenderer deaktivieren AWT, Swing, JavaFX & SWT 13
J TableCellRenderer AWT, Swing, JavaFX & SWT 5
S JTree mal anders (TableCellRenderer) AWT, Swing, JavaFX & SWT 6
S TableCellRenderer, Performance AWT, Swing, JavaFX & SWT 9
M Objekt in TableCellRenderer packen, warum ein Fehler? AWT, Swing, JavaFX & SWT 2
T TableCellRenderer Problem AWT, Swing, JavaFX & SWT 6
B TableCellRenderer + JComboBoxen AWT, Swing, JavaFX & SWT 2
G Swing JTable prepareRenderer überschreiben? AWT, Swing, JavaFX & SWT 4
G JTable - prepareRenderer() überschreiben klappt nicht AWT, Swing, JavaFX & SWT 2
S Wann brauche ich die prepareRenderer() Methode ? AWT, Swing, JavaFX & SWT 2

Ähnliche Java Themen

Neue Themen


Oben