jTable und farbige Spalten

Timo.

Mitglied
Hallo zusammen,

ich bin gerade dran ein kleines Programm zur Überwachung von Überweisungen zu schreiben.
Beim starten des Programms werden die offenen Überweisungen aus der Datenbank geladen und in einen Vector geschrieben. Dieser Vector wird dann mit der Methode setDataVector(...) dem TableModerl übergeben, das ich zuvor erstellt habe. Soviel dazu. Die Daten werden in der jTable ausgegeben. Zur Erinnerung daran, das die Überweisungen rechtzeitig getätigt werden, kann ich einen Wert setzen, der so und so viel Tage davor warnt das noch ausstehende Überweisungen getätigt werden müssen.

Nach dem Füllen der jTable läuft eine Routine ab, die überprüft, welche Überweisungen noch getätigt werden muss und welche übnerfällig ist. Dementsprechend wird ein Flag gesetzt. Anhand diesem Flag möchte ich später die anstehenden Überweisungen orange und die überfälligen rot in der jTable färben.

Wie in der API habe ich eine neue Klasse, die vom DefaultTableCellRenderer erbt erstellt.

Der Code sieht so aus:

Java:
public class TableRenderer extends DefaultTableCellRenderer {

    @Override
    public java.awt.Component getTableCellRendererComponent(JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
       
        return this;
    }
}

Das in der Klasse noch eine Routine implementiert werden muss, das die row abprüft und dementsprechend den Background anders färbt ist mir klar. Habe ich auch schon ausprobiert.

Da liegt auch das Problem. Wenn ich das so implementiere, das die Flags überprüft werden und dementsprechend die Farben gesetzt werden, wird immer nur die letzte Zeile die die in der Routine behandelt wird eingefärbt.

Für mich schaut das so aus, als ob nach jedem Durchlauf die zuvor gesetzte Farbe der Zeile wieder rückgesetzt wird und die nächste eingefärbt wird.

Was mache ich falsch ??

Gibt es auch eine andere Methode um die gesamte Tabelle nach den oben genannten Kriterien farblich zu kennzeichnen?

Vielen Dank Gruß Timo.
 
Für mich schaut das so aus, als ob nach jedem Durchlauf die zuvor gesetzte Farbe der Zeile wieder rückgesetzt wird und die nächste eingefärbt wird.
Du hast das ja im Prinzip richtig verstanden. Renderer funktionieren immer so, dass für jede Zelle einzeln die getXYZRenderer(…)-Methode aufgerufen wird. Diese richtet eine Komponente ein und gibt sie zurück. Dann wird die Komponente gezeichnet und dann wird mit der nächsten Zelle weiter gemacht. Funktioniert im Prinzip wie stempeln mit so einem typischen Datumsstempel. Die Renderer-Komponente ist dabei der Stempel. Der Renderer setzt in getXYZRenderer(…) das jeweilige Datum des Stempels und färbt ihn ein und so weiter. Die Tabelle drückt dann den Stempel aufs Papier. Dann fragt sie wieder den Renderer für die nächste Zelle, er stellt ein ganz anderes Datum am Stempel ein und nimmt ein anderes Stempelkissen. Die Tabelle stempelt dann wieder den selben Stempel (mit anderem Datum und anderer Farbe).

Aber was jetzt Dein eigentliches Problem ist, kann ich aus Deinem Beitrag nicht erkennen. Wahrscheinlich setzt Du erst den Hintergrund und rufst dann die [c]super[/c]-Implementierung auf die dann die Farbe wieder ändert. Oder etwas in der Art. Mach Doch mal ein einfaches Beispiel für einen Renderer der nicht funktioniert.

Ebenius
 
So also in meiner Klasse in der ich den Renderer aufrufe sieht so aus:

Java:
TableRenderer tablerenderer = new TableRenderer();
            tablerenderer.setOffene_auftraege(offene_auftraege);
            manager.jTable_offene_Zahlungen().setDefaultRenderer(Object.class, tablerenderer);

offene_auftraege ins der Vector der alle meinen offenen Aufträge beinhaltet, die auch in der jTable stehen

Die Klasse TableRenderer sieht mittlerweile so aus:

Java:
 public Vector<Kunde> offene_auftraege;
    public int zeilenzaehler;

    public void setOffene_auftraege(Vector<Kunde> offene_auftraege) {
        this.offene_auftraege = offene_auftraege;
    }

    @Override
    public java.awt.Component getTableCellRendererComponent(JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        for (int i = 0; i < offene_auftraege.size(); i++) {
            for (int j = 0; j < offene_auftraege.get(i).getAuftraege().size(); j++) {

                if (row == zeilenzaehler && (offene_auftraege.get(i).getAuftraege().get(j).getFaellig() == 1 || offene_auftraege.get(i).getAuftraege().get(j).getUeberfaellig() == 2)) {
                    if (row == zeilenzaehler && offene_auftraege.get(i).getAuftraege().get(j).getFaellig() == 1) {
                        setBackground(Color.ORANGE);
                    }
                    if (row == zeilenzaehler && offene_auftraege.get(i).getAuftraege().get(j).getUeberfaellig() == 2) {
                        setBackground(Color.RED);
                    }
                } else {
                    setBackground(Color.WHITE);
                }
                zeilenzaehler++;
                row++;
                setOpaque(true);
            }
        }
        return this;
    }
}

Die Ausgabe in der Tabelle sieht so aus:

Programm.jpg ... at uploaded.to - Free File Hosting, Free Image Hosting, Free Music Hosting, Free Video Hosting, ...

Dabei sollte der erste Eintrag in der Tabelle rot sein, der zweite orange und der dritte normal.

In meinem Fall ist jetzt aber gar nichts markiert.

Habe ich da was an dem Prinzip falsch verstanden?

Was muss ich ändern ? bzw. wo liegt hier der Hund begraben?

Gruß Timo.
 
Zuletzt bearbeitet:
In meinem Fall ist jetzt aber gar nichts markiert.

Habe ich da was an dem Prinzip falsch verstanden?
Ja, hast Du.

Probier's doch erstmal -- zum Verständnis -- mit nem ganz einfachen:
Java:
new DefaultTableCellRenderer() {

    @Override
    public java.awt.Component getTableCellRendererComponent(JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        if(!isSelected) {
            switch(row % 3) {
            case 0:
                setBackground(Color.RED);
                break;
            case 1:
                setBackground(Color.ORANGE);
                break;
            case 2:
                break;
            }
        }
    
    return this;
    }
};
Ein CellRenderer kümmert sich in der getTableCellRenderer(…)-Methode immer nur um eine Zelle, um die die durch [c]row[/c] und [c]column[/c] angegeben ist. For-Schleifen in dieser Methode sind fast immer falsch. 🙂

Ebenius
 
@Ebenius

Danke!!

Mit dem Code von Dir funktioniert es. Ich habe aber auch schon davor etwas Einfacheres versucht das auch funktioniert hat. Wenn du sagst das for Schleifen im Renderer fast immer falsch sind, wo soll dann die Prüfung gemacht werden nach der entschieden wird welche Spalte jetzt rot, orange, oder weiß werden soll?

Gruß Timo.
 
Ich sag ja nur "fast". Die Schleifen oben verstehe ich nicht ganz, weil ich das Umfeld nicht kenne. Aber spätestens das [c]row++[/c] in Zeile 31 scheint mir ein Indiz für einen Denkfehler zu sein. Denn [c]row[/c] identifiziert ja genau die eine Zeile die der Renderer darstellen soll…

Natürlich braucht man ab und an auch mal ne Schleife in einem Renderer, um irgendwas zu suchen was zur aktuellen Zelle passt. Schuldig. 😱

Ebenius
 
Ja das row++ ist falsch.

Ich habe jetzt mal den kompletten Fall debugt und mir war vorher nicht klar das sich row nicht von selbst inkrementiert.

Ich weiß jetzt auch warum das mit meiner Schleife nicht funktioniert. Und zwar weil bei jedem Schleifendurchgang ja der Teil
Java:
  if (!isSelected) {
            switch (row % 3) {
                case 0:
                    setBackground(Color.RED);
                    break;
                case 1:
                    setBackground(Color.ORANGE);
                    break;
                case 2:
                    break;
            }
        }
Und dieser Teil ja jedes Mal die gesamte Tabelle durchläuft. Deshalb wird mit jedem Schleifendurchlauf die vorher eingefärbten Spalten wieder überschrieben.


Mir ist nur noch nicht so ganz klar wie ich das dann jetzt anders machen soll!

Vielen Dank an Alle Gruß Timo
 
Um das einschätzen zu können, müsste ich wissen, wie [c]offene_auftraege[/c] in Bezug zu Deinem Tabellenmodell steht.

Ebenius
 
in offene_Auftraege sind allen offenen Auftraege, die auch in der Tabelle stehen. Also Objekte der Klasse Auftrag. In der Klasse Auftrag gibt es zwei Flags. Eins falls der Auftrag überfällig ist dann hat das Flag (int ueberfaellig) den Wert 2. Ist der Auftrag fällig, so hat das Flag (int faellig) den Wert 1.

Das muss jetzt überprüft werden. Deshalb die Schleife.

Überfällige Auftäge sollen rot, fällige orange und der Rest ganz normal weiß gekennzeichnet werden.

Gruß Timo.
 
Du willst also einfach einen Renderer in der Art?
Java:
new DefaultTableCellRenderer() {
 
    @Override
    public java.awt.Component getTableCellRendererComponent(JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        final Auftrag auftrag = (Auftrag) value;
        if(!isSelected) {
            if (auftrag.getUeberfaellig() == 2) {
                setBackground(Color.RED);
            } else if (auftrag.getFaellig() == 1) {
                setBackground(Color.ORANGE);
            }
        }
    
    return this;
    }
};
Ebenius
 
Ja im Prinzip schon, nur das die Flags nicht in der Tabelle stehen
Dann willst Du sowas? Ein bisschen mitdenken darfste schon auch noch. ;-)
Java:
new DefaultTableCellRenderer() {
 
    @Override
    public java.awt.Component getTableCellRendererComponent(JTable table,
            Object value,
            boolean isSelected,
            boolean hasFocus,
            int row,
            int column) {
        super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);

        if (!isSelected) {
            final List<Auftrag> offen = offene_auftraege.get(table.convertRowIndexToModel(row)).getAufträge();
            for (Auftrag auftrag : offen) {
                if (auftrag.getUeberfaellig() == 2) {
                    setBackground(Color.RED);
                } else if (auftrag.getFaellig() == 1) {
                    setBackground(Color.ORANGE);
                }
            }
        }
    
    return this;
    }
};
Ebenius
 
Ich bin gerade dabei das so umzustricken dass das mit deinem ersten Vorschlag funktioniert. Bin jetzt auch eigentlich so weit, nur meckert er jetzt .. cannot cast Integer to Auftraege
 
So Ebenius


Da es leider nicht klappt bin ich jetzt umgeschwenkt.
Mittlerweile habe ich in die Tabelle zwei Spalten (überfällig und fällig) eingefügt, in denen dann ja oder nein steht.

Jetzt versuche ich dieses abzuprüfen und dementsprechend die Spalten zu färben.

Es scheitert nur daran im Renderer die passende Methode zu finden um aus table den String ja oder nein zu bekommen.
 

Zurück
Oben