Swing Swing macht sehr seltsame Zeichnungen.

shidan

Mitglied
Hallöchen.

Ich habe ein etwas seltsames Problem mit meiner kleinen GUI.
Sie besteht aus einem JTable , Scrollpane und MenuBar.

10xvs0m.jpg


Ein Bild zur ungefähren verständniss (nichtmehr 100% aktuell)

Das Problem ist nun, wenn ich z.B runterscrolle, wieder hoch. Färbt sich die Table wieder irgendwie durcheinander. Draufklicken (markieren) macht es genauso schlimm. Manchmal ist die Tabelle nur zur Hälfte gefärbt und es sieht aus wie abgeschnitten oder mein Tooltip der eigentlich nur auf die RadioButtons in den ersten beiden Spalten reagieren sollte zeigt sich überall.

Hier damit man das Mysterium mal genauer sieht.

2cnifif.jpg
 
Zuletzt bearbeitet:
Irgendwo Swing und AWT gemicht? Eigene CellRenderer vielleicht falsch implementiert? (Obwohl es nach letzterem nicht so aussieht...)
 
An AWT's hab ich nur drinn
Java:
import java.awt.Color;
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

Render weiß ich nicht

Java:
import java.awt.Color;
import java.awt.Component;

import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;

	/**
	 * ColoredTableRender um die Tabelle einzufärben.
	 */
	public class CustomTableCellRenderer  extends
	    DefaultTableCellRenderer {			

		private static final long serialVersionUID = 1L;		
		  private Color colorSelected = new Color(94, 129, 188 );
	//	  private Color colorFocus = new Color( 94, 129, 188 );
		  private Color colorNormal =Color.WHITE;
		  private Color lightgray = new Color(210,210,210);
		  boolean isWhite;
		

		public Component getTableCellRendererComponent (JTable table, 
		  Object obj, boolean isSelected, boolean hasFocus, int row, int column) {
			  super.getTableCellRendererComponent(
			   table, obj, isSelected, hasFocus, row, column);	
                setForeground(Color.black);
                ((JLabel)table.getDefaultRenderer(String.class)).setHorizontalAlignment (JLabel.RIGHT); 
                if(column == 0 && row == 0){
                	isWhite = true;
                }
                if(isWhite){
                	setBackground(colorNormal);
                }else if(!isWhite){
                	setBackground(lightgray);
                }        
                if( isSelected){            
                	setBackground(colorSelected);
                    setForeground(colorNormal); 
                }
     
                else{  
                	if(column == 0){
	                    if(row > 0){                    	
	                       if(!table.getValueAt(row, 0).equals(table.getValueAt(row-1, 0))){
	                    	  if(isWhite){
	                    		  setBackground(lightgray);	                    	
	                    		  isWhite = false;
	                    	  }else{
	                    	
	                    		  setBackground(colorNormal);
	                    		  isWhite = true;
	                    	  }
	                       }
	                    }
                	}                
                }  
		     return this;
		  }
	}

Oder leigt es vielleicht an der Stelle hier
Java:
		DefaultTableCellRenderer renderer = 
			new CustomTableCellRenderer ();
		
		tColumnNames.setCellRenderer(renderer);
		tColumnProjekts.setCellRenderer(renderer);	
		jTable.setDefaultRenderer(this.getClass(), renderer);

Meine Renderer Klasse falls es hillft.
 
Zuletzt bearbeitet:
Könntest mal das Einfärben der Zeilen ohne eigenen Renderer, sondern nur durch Überschreiben der prepareRenderer der JTable umsetzen und probieren, ob das Phänomen auch hierbei auftritt.
Ansonsten könnte man auch probieren, ob Änderungen mittels setScrollMode(...) am JViewport der Scrollpane die Anzeige verbessern. Wobei bei Dir das Problem ja auch bei der Selektion auftritt?
Java:
import java.awt.Color;
import java.awt.Component;

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


public class ColoredRowTableDemo extends JFrame {
	private JTable table;
	public ColoredRowTableDemo() {
		DefaultTableModel model = new DefaultTableModel(new Object[][] {
				{"Name 1", "A"},
				{"Name 1", "B"},
				{"Name 1", "C"},
				{"Name 2", "D"},
				{"Name 2", "E"},
				{"Name 3", "F"},
				{"Name 4", "G"},
				{"Name 4", "H"},
				{"Name 5", "I"},
				{"Name 5", "J"}},
				new String[] {"Name", "Projekt"}
		);
		table = new JTable(model) {
			//überschrieben, um die Zeilenfarbe zu setzen.
			public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
				Component c = (Component) super.prepareRenderer(renderer, row, column);
				if (table.getSelectedRow() == row) {
					c.setBackground(table.getSelectionBackground());
					return c;
				}
				if (row>0 && table.getValueAt(row, 0).equals(table.getValueAt(row-1, 0)))
					c.setBackground(Color.LIGHT_GRAY);
				else
					c.setBackground(table.getBackground());
				return c;
			}
		};
		this.getContentPane().add(new JScrollPane(table));
	}

	public static void main(String[] args) {
		JFrame frame = new ColoredRowTableDemo();
		frame.setBounds(0, 0, 500, 300);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
 
Soweit ich das überflogen habe sieht das richtig aus. Dann würden mir spontan nur noch "die üblichen Verdächtigen" einfallen: Sicherstellen, dass JDK/JRE und Grafikkartentreiber auf dem aktuellsten Stand sind...:bahnhof:
 
Der Algroythmus zum färben war jetzt nicht genau der richtige aber ansonten habe ich den Fehler nichtmehr. Ich stelle ihn nocheinmal um und sage dann nocheinmal Bescheid.

Wieder der schöne Fehler zwar nicht genau so, aber ähnliche wie z.B nur 1 HellGrauer Strich mitten in der Reihe und beim Selectieren klappts auch nicht.

Vielleicht ist ja irgendetwas falsch habe es jetzt so umgeschrieben.

Java:
			jTable = new JTable(dtm) {
            //überschrieben, um die Zeilenfarbe zu setzen.
			 public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
	                Component c = (Component) super.prepareRenderer(renderer, row, column);
	                c.setForeground(Color.black);
	                if(isWhite){
	                    c.setBackground(Color.white);	                    
	                }else if(!isWhite){
	                    c.setBackground(Color.LIGHT_GRAY);
	                }   
	                for(int i = 0; i < jTable.getSelectedRows().length;i++){
		                if (jTable.getSelectedRows()[i] == row) {
		                    c.setBackground(jTable.getSelectionBackground());
		                    c.setForeground(Color.white);
		                    return c;
		                }	   
	                }
	                if(column == 0){
		                if (row >0 && !jTable.getValueAt(row, 0).equals(jTable.getValueAt(row-1, 0))){
		                		if(isWhite){
		                			c.setBackground(Color.LIGHT_GRAY);
		                			isWhite= false;
		                		}else{
		                			c.setBackground(Color.white);
		                			isWhite = true;
		                		}
		                	}
		                return c;
	                }else{
	                	if(isWhite)
	                		c.setBackground(Color.white);
	                	else
	                		c.setBackground(Color.LIGHT_GRAY);
	                	return c;
	                }	                
	            }
			 
	        };

Edit: Merfache RowSelection eingebaut.
JDK & JRE sowie GrafikartenTreiber sind auf dem neusten Stand.
Was ein gemeiner Fehler :|
 
Zuletzt bearbeitet:
Das isWhite könnte zumindest ein Teil des Problems sein. Die Einfärbung muss anhand "unabhängigen" Kriterien definiert werden. Da man keinen Einfluss hat in welcher Reihenfolge die Zellen gerendert werden, wird auch das isWhite unkontrolliert gesetzt.

Nach welchen Regeln sollen die Zeilen denn eingefärbt werden?
 
Die Tabelle soll wie im ersten Post 2tes Bild gefärbt werden.
Die Farbe soll ich für die Komplette Reihe ändern sobald ein anderer Name festgestellt und diese Farbe solange behalten bis der Name sich erneuert ändern usw.
Damit es übersichtlicher und leichter zu lesen wird.
Ich wüsste leider nicht wie ich das sonst noch umsetzen soll, da sich die Tabelle ohne das isWhite ziemlich durcheinander färbt. Weiß Grau Weiß Grau usw.

Ich werde mich am besten trozdem noch einfach mal drannsetzen.



Edit:
Gerade ist mir aufgefallen das das Frame 2 Pixel zu lang war, wenn ich die Größe nun so setze das es mit den Tabellen perfekt übereinstimmt habe ich nichtmehr wirklich schlimme Fehler. Die Farbe springt nurnoch weiter herum wenn ich die Größe verändere.
Beim Selektieren tut er es leider auch so immernoch.
 
Zuletzt bearbeitet:
Gerade ist mir aufgefallen das das Frame 2 Pixel zu lang war, wenn ich die Größe nun so setze das es mit den Tabellen perfekt übereinstimmt habe ich nichtmehr wirklich schlimme Fehler. Die Farbe springt nurnoch weiter herum wenn ich die Größe verändere.
Beim Selektieren tut er es leider auch so immernoch.
?? Wie kann ein Frame zwei Pixel zu lang sein? Was genau machst Du da?

Warum machst Du die Überprüfung (column==0) ? Ich dachte die Zeile soll durchgehend einheitlich eingefärbt werden?
 
Die Größe war 2 Pixel zu viel, man hat noch ein kleines Stück der nächsten Spalte gesehen und dieses Stück färbte er immer mit ein.

Zu Column 0 , er macht nur wenn die Spalte 0 ist die Abfrage weil dann eigentlich der Background gesetzt sein sollte.
Die anderen Collumns holen sich halt nur den True oder False aus isWhite und färben sich dementsprechend.
Ohne das Färbte er mir entweder alles ganz durcheinander oder nur die erste Zeile

Um genauer zu sein.

i6dppy.jpg
 
Zuletzt bearbeitet:
Nur um das nochmal klar zu stellen:
Ziel soll es sein, dass die erste Zeile eines Namens komplett weis bleibt. In den folgenden Zeilen (mit dem selben Namen in der ersten Spalte) sollen alle Zellen anders eingefärbt werden.
Sobald ein neuer Name in der ersten Spalte auftaucht soll die komplette Zeile wieder weis bleiben.

Wenn dem so ist, dann wird das ja genau durch diese Zeilen umgesetzt:
Java:
if (row>0 && table.getValueAt(row, 0).equals(table.getValueAt(row-1, 0)))
    c.setBackground(Color.LIGHT_GRAY);
else
    c.setBackground(table.getBackground());
Hier werden unabhängig davon in welcher Zeile die zu renderende Zelle steckt, die Werte der ersten Spalte miteinander verglichen.

Eventuell kannst Du ja mal kompilierbaren Bsp Code posten, mit dem man das Problem nachstellen kann.
 
Nur um das nochmal klar zu stellen:
Ziel soll es sein, dass die erste Zeile eines Namens komplett weis bleibt. In den folgenden Zeilen (mit dem selben Namen in der ersten Spalte) sollen alle Zellen anders eingefärbt werden.
Sobald ein neuer Name in der ersten Spalte auftaucht soll die komplette Zeile wieder weis bleiben.

....


Nein gerade eben nicht so.
Die Namen die gleich sind sollen auch die gleiche Farbe besitzen und die Farbe soll wechseln sobald der Name sich verändert und dann solange in dieser Farbe bleiben bis der Name wieder wechselt.
Ich kriege das ja schon so weitesegehend hin nur halt habe ich immer die Selektier Fehler.

Hier mal um es genauer zu verstehen:
So soll es aussehen.
21o9d7d.jpg


Uff Code posten.
Da würde nen Stück zusammenkommen und hässlich geschrieben ist er auch ;D
Dazu wäre das alles umzuschreiben zuviel Arbeit besonders da ich gerad auf der Arbeit hocke.
Hätte niemals gedacht das daraus so ein seltsamer Fehler entsteht ^^

Ich hab hier mal das Gezippte Eclipse Projekt dranngehangen da die Einträge aus txt dateien gelesen/gespeichert werden.
 

Anhänge

Zuletzt bearbeitet:
Nein gerade eben nicht so.
Die Namen die gleich sind sollen auch die gleiche Farbe besitzen und die Farbe soll wechseln sobald der Name sich verändert und dann solange in dieser Farbe bleiben bis der Name wieder wechselt.

Achso, da hab ich das die ganze Zeit falsch verstanden.
In dem Fall reicht es nicht aus, wenn man versucht es nur über einen Renderer zu regeln.

Hier mal eine Möglichkeit. Ich verwende ein Color-Array als "Model" für die Farbwerte der einzelnen Zeilen. Der Einfachheit halber und zu Demozwecken habe ich JTable überschrieben - muss aber nicht sein.
Java:
import java.awt.Color;
import java.awt.Component;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.event.TableModelEvent;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableModel;


public class ColoredGroupTableDemo extends JFrame {
	private JTable table;
	public ColoredGroupTableDemo() {
		DefaultTableModel model = new DefaultTableModel(new Object[][] {
				{"Name 1", "A", null, null},
				{"Name 1", "B", null, null},
				{"Name 1", "C", null, null},
				{"Name 2", "D", null, null},
				{"Name 2", "E", null, null},
				{"Name 2", "X", null, null},
				{"Name 2", "Y", null, null},
				{"Name 3", "F", null, null},
				{"Name 4", "G", null, null},
				{"Name 4", "H", null, null},
				{"Name 5", "I", null, null},
				{"Name 5", "J", null, null}},
				new String[] {"Name", "Projekt", "KW26", "KW27"}
		);
		table = new GroupingTable(model, 0);
		this.getContentPane().add(new JScrollPane(table));
	}
	
	class GroupingTable extends JTable {
		private int keyColumn;
		private Color[] colorModel;
		private int[] colorIndex;	//"Model" zur Speichern der Zeilenfarbe
		
		public GroupingTable(TableModel model, int column) {
			super(model);
			this.keyColumn = column;
			colorModel = new Color[] {this.getBackground(), Color.LIGHT_GRAY};
			determineColor();
		}
		
		//tableChanged überschrieben, damit das "Farbenmodel" aktualisiert wird
		public void tableChanged(TableModelEvent evt) {
			if (evt.getColumn()==keyColumn)
				determineColor();
			super.tableChanged(evt);
		}
		
		//Methode zum Ermitteln der Zeilenfarbe
		private void determineColor() {
			colorIndex = new int[this.getRowCount()];
			if (colorIndex.length<=0)
				return;
			int colorCount=0;
			colorIndex[0] = colorCount;
			for (int row=1; row<this.getRowCount(); row++) {
				if(this.getValueAt(row, this.convertColumnIndexToView(keyColumn))
						.equals(this.getValueAt(row-1, this.convertColumnIndexToView(keyColumn))))
					colorIndex[row] = colorCount & 1;
				else
					colorIndex[row] = ++colorCount & 1;
			}
		}
		
		//überschrieben, um die Zeilenfarbe zu setzen.
		public Component prepareRenderer(TableCellRenderer renderer, int row, int column) {
			Component c = (Component) super.prepareRenderer(renderer, row, column);
			for (int i=0; i<this.getSelectedRows().length; i++) {
				if (this.getSelectedRows()[i]==row)
					return c;
			}
			c.setBackground(colorModel[colorIndex[row]]);
			return c;
		}
	}
	
	public static void main(String[] args) {
		JFrame frame = new ColoredGroupTableDemo();
		frame.setBounds(0, 0, 500, 300);
		frame.setLocationRelativeTo(null);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setVisible(true);
	}
}
 
Wow klappt, wenn ich es so umsetze in meinen Code, Super.
Wenn ich mir das so anschaue sieht das dann doch etwas komplizierter aus als ich vorher dachte.

Dennoch danke, das war das gemeinste Problem was ich zur Zeit mit der Tabelle hatte ^^
 

Neue Themen


Zurück
Oben