JTable Zeilen und Zellen einfärben

may24

Bekanntes Mitglied
Hi zusammen,

ich habe folgendes Anliegen.

Ein JTable ist gefüllt mit mehreren Zeilen + Spalten von Daten. Nun möchte ich die angewählte Zeile farblich vom Rest abheben. Zusätzlich soll die angewählte Zelle innerhalb dieser Zeile eine andere Farbe bekommen.
Wird eine neue Zeile (+ Zelle) angeklickt, soll die alte Zeile wieder ihre "Ursprungs-Hintergundfarbe" bekommen.

Hier ist mein custom TableCellRender. Da ich Cell-selection habe funktioniert der im Moment nur bei einer selektierten Zelle und läßt die Zeile unverändert.

Java:
public class MyTableCellRender extends DefaultTableCellRenderer   
{
	private Vector<Integer> lineColors;
	private Color[] segmentColors = new Color[2];
	private int cIdent = 0;
	
	public MyTableCellRender()
	{
		segmentColors[0] = new Color(240,240,240);
		segmentColors[1] = new Color(220,220,220);
		
	}
	
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
    {
    	Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    	
    	if (isSelected) 
    	{
            c.setBackground(new Color(231,243,253));    
            // System.out.println("TableCellRender: " + row);
            
        }
    	else
    	{
    	cIdent = lineColors.get(row);
    	c.setBackground(segmentColors[cIdent]);
    	}
    	
    	return c;
    }
    
    public void updateLineColor(Vector<Integer> lineColorVector)
    {
    	lineColors = lineColorVector;
    }
}
 
Hi, danke für den Link, aber ich habe da nichts passenden/funktionierendes gefunden.
Wie schon erwähnt ist Cell Selection eingeschaltet und da ich hier nitcht mit "value instanceof" arbeiten kann - da die von Fall zu Fall unterschiedlich ist - wird immer nur das "Component" eigefärbt das "selected" ist, und nie die Ganze Zeile.

Man müßte irgentwie an die Components einer kompletten Zeile kommen und deren Background setzen ...
 
Nun möchte ich die angewählte Zeile farblich vom Rest abheben. Zusätzlich soll die angewählte Zelle innerhalb dieser Zeile eine andere Farbe bekommen.
Inwieweit unterscheiden sich Deine Anforderungen vom Standardverhalten der JTable?

Ist die Zelle in der selektierten Zeile ist isSelected==true
Ist die Zelle die selektierte Zelle ist hasFocus==true
 
es ist wichtig zu verstehen, dass es schlicht keine derartigen Components dauerhaft gibt,
die JTable wird einfach gezeichnet, nach und nach wird für jede Zelle eine simple paint-Methode durchlaufen,
danach merkt sich irgendjemand hoffentlich die Pixel, sonst war es umsonst, aber ansonsten ist kein Zustand mehr bekannt,

richtig ist dass der Renderer eine handfeste Komponente wie ein JLabel zurückgibt, bei dem man auch durchaus den Background setzen kann,
aber nur damit in Kürze darin paint() ausgeführt werden kann, ein paar ms später interessiert sich niemand mehr für dieses Label,
außer wenn es in anderer Funktion, z.B. für die nächste Zelle, schon wieder verwendet wird

du kannst dir (vom SelectionListener aus) irgendwo die Information ablegen 'Zeile x = blau'
und im Renderer weißt du durch den Parameter, welche Zeile gerade malt wird und setzt danach den Background
 
@Michael: Wenn du [c]setCellSelectionEnabled(true)[/c] gesetzt hat, kannst du nur Zellen und keine kompletten Zeilen markieren.
Daher funktioniert das [c]hasFocus[/c] nicht so wie ich es brauche. Du kannst zwar mehrere Zellen markieren und die werden dan auch andersfarbig dargestellt, aber nie die komplette Zeile.

Ich befürchte mal es wird tatsächlich nur über einen weiteren ListSelectionListener gehen ...
 
das mit dem setCellSelectionEnabled hatte ich übersehen.

Meinst Du so etwas in der Art?
Java:
import java.awt.Color;
import java.awt.Component;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.table.TableCellRenderer;

public class TableTest {

	public static void main(String[] s) {
		new TableTest();
	}

	public TableTest() {
		JFrame frame = new JFrame();
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

		JTable table = new JTable(5, 5) {
			public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
				Component comp = super.prepareRenderer(renderer, row, column);
				int selRow = this.getSelectedRow();
				int selCol = this.getSelectedColumn();
				comp.setBackground(this.getBackground());
				if (row==selRow) {
					if (column==selCol)
						comp.setBackground(Color.RED);
					else
						comp.setBackground(Color.BLUE);
				}
				return comp;
			}
		};
		
		table.setCellSelectionEnabled(true);
		table.getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
		

		frame.add(new JScrollPane(table));
		frame.setBounds(0, 0, 200, 200);
		frame.setVisible(true);
	}
}
 
Hi zusammen

Ich hab's immer noch nicht hinbekommen ;(

OK, Ich habe neben meinem TableCellRender der die Zelle farblich markiert nun auch einen ListSelection implementiert der mir die Zeilen einfärben soll. Nur wie ?
Mit
Code:
getSelectedRows()
bekomme ich zwar ein Array mit den entsprechenden Zeilen, doch wie diese mit
Code:
setBackground()
setzen ?
Kann ich durch "table" direkt eine Zeile ansprechen ? Und wenn ja wie ? :autsch:
 
wie gesagt, es gibt den direkten Weg nicht,
- du musst du Information irgendwo auf irgendeine Weise ablegen (* oder auch nicht)
- evtl. das repaint() der fraglichen Zeilen veranlassen
- und dann erst im Renderer (für jede Zelle neu) entweder aus den selber abgelegten Informationen oder (*) aus dem SelectionModel der Tabelle die Informationen holen,
und dann mit allen nötigen Informationen dafür sorgen dass die aktuelle Zelle richtig dargestellt werden
 
Hi zusammen,

ich glaube ich bin dem Ganzen ein Stück näher gekommen.
Ich habe also nun einen Vector der zwei Zahlen speichert. Die Aktuelle Fare un die Original Farbe.
Der ListSelector nimmt das Array der selektierten Zeilen von JTable und übergibt sie meinem TableCellRender der wiederum den Vector mit der Farbinformation abgleicht.
Soweit so gut: Erst mal nach jedem selektieren eine Zeile den Vektor mit den "original Farbwerten" versehen, dann die entsprechend selektierten Zeilen im Vector so abändern das sie auf eine neue Farbe zeigen.
Was jetzt noch fehlt ist ein Event das den TableCellrender dazu veranlasst alles neu zu zeichnen.
[c]repaint()[/c] macht da gar nichts. Ist es nicht eher ein fireTableCellRender... ?

Hier ist der Code für MyTableCellRender:
Java:
...
public class MyTableCellRender extends DefaultTableCellRenderer   
{
	private Vector<int[]> lineColors;
	private Color[] segmentColors = new Color[3];
	private int cIdent = 0;
	
	public MyTableCellRender()
	{
		segmentColors[0] = new Color(240,240,240);
		segmentColors[1] = new Color(220,220,220);
		segmentColors[2] = new Color(192,220,192);
		
	}
	
    public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column)
    {

    	Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
    	
    	if (isSelected) 
    	{
            c.setBackground(new Color(231,243,253));
        }
    	else
    	{
    		int[] tmpArray = lineColors.get(row);
    		cIdent = tmpArray[0];
    		c.setBackground(segmentColors[cIdent]);
    	}
    	return c;
    }
    
    public void updateLineColorVector(Vector<int[]> lineColorVector)
    {
    	lineColors = lineColorVector;
    }
    
	public void updateLinesFromListSelector(int[] selectedLines)
    {
    	// first: cleanup
    	int rounds = lineColors.size();
    	for ( int i = 0; i< rounds; i++)
    	{
    		int[] tmpLine = lineColors.get(i);
    		tmpLine[0] = tmpLine[1];
    		System.out.println(tmpLine[0]);
    		lineColors.set(i, tmpLine);
    	}
    	
    	// modify the selected lines
    	rounds = selectedLines.length;
    	for ( int i = 0; i< rounds; i++)
    	{
    		int affectedLine = selectedLines[i];
    		int[] tmpLine = lineColors.get(affectedLine);
    		int[] newLine = new int[] { 2, tmpLine[1]};
    		lineColors.set(affectedLine, newLine);
    	}

    	//repaint ??
    }
}
 
genau, fire() in TableModel, welche es da gibt für evtl. zeilengenaues Update kann man nachschlagen,
im Zweifel ist fireTableDataChanged() immer relativ gut
 
Ah ... ein einfaches [c]table.repaint()[/c] langt eigentlich schon.
Obwohl das Ganze ziemlich langsam ist ... Aber ich befürchte mal das liegt in der Natur der Sache.
Sprich wenn man die Farbinformation in einem Vector speicert und so benutzt wie ich das tue dauert's halt mit dem repaint ...

Auch wenn ich die Methode in mein DataModel "auslagere" wird's nicht schnelle. Und je mehr Zeilen/Zellen dazukommen desto langsamer wirds logischerweise.

Oder hat jemand noch 'ne Idee ?
 
Zuletzt bearbeitet:

Zurück
Oben