Zeile in mehreren Jtables bei Selektion markieren

fredi

Mitglied
Hallo ich hoffe ihr könnt mir bei folgender Frage helfen 🙂

Ich habe 2 Jtables und möchte wenn ich eine Zelle anklicke die komplette Zeile auf beiden Tabellen markieren. Leider hab ich das bisher nicht hinbekommen.

Folgendes Snippet:

// markiert nur die Zeile in der aktuellen Tabelle
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {

Component comp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);


if (isSelected) {


setBackground(table.getSelectionBackground());
} else {
setBackground(table.getBackground());
}
return comp;

}



// Idee MouseAdapter aber komme dort nicht weiter 🙁
public class Action extends MouseAdapter {


JTable[] tables;

JTable table;

public Action (JTable table, JTable... tables) {
this.tables= tables;
this.table = table;
}

public void mousePressed(MouseEvent e) {
int clickedViewRow = this.table.rowAtPoint(new Point(e.getX(), e.getY()));


int clickedModelRowIndex = this.table.convertRowIndexToModel(clickedViewRowIndex);
for (JTable table : this.tables) {

..... wie kann ich nun die komplette Zeile markieren?


}


}



Danke im Voraus und viele Grüße
 
1. Vergiss Mouseevents, arbeite mit dem TableSelectionModel
2. Die Farben zu ändern, geht ebenfalls am Problem vorbei.

Wenn du wirklich selektieren willst, dann ist die Methode dafür setRowSelectionInterval(rowIndexFirstRow, rowIndexLastRow).

Hier hab ich auf die schnelle mal einen kurzen Code zusammengezimmert, der berücksichtigt eventuell noch nicht alle Fälle, funktioniert aber grundsätzlich
[CODE lang="java" title="Beispielcode"] public MyFrame() {
//... //
//Das Selektieren der gesamten Zeile erlauben
jTable1.setRowSelectionAllowed(true);
jTable2.setRowSelectionAllowed(true);
//Falls nicht bekannt: Habe hier einen Lambdaaustruck verwendet.
//Hier wird ein ListSelectionListener erzeugt und dem Modell hinzugefügt, der EventParameter e wird ignoriert, da nicht von Belang.
jTable1.getSelectionModel().addListSelectionListener(e -> synchronizeSelection(jTable1, jTable2)); //Index von jTable1 nach jTable2 übertragen
jTable2.getSelectionModel().addListSelectionListener(e -> synchronizeSelection(jTable2, jTable1)); //Index von jTable2 nach jTable1 übertragen
}

/**
* Setzt den RowselectionIndex der Tabelle tSlave auf den Index der ersten markierten Zeile von tMaster.
*/
private void synchronizeSelection(JTable tMaster, JTable tSlave) {
int row1 = tMaster.getSelectedRow();
int row2 = tSlave.getSelectedRow();
// Nur ausführen, wenn sich die Werte unterscheiden, sonst landen wir in einer Endlosschleife.
if (row2 != row1) {
tSlave.setRowSelectionInterval(row1, row1);
}
}
[/CODE]
 
1. Vergiss Mouseevents, arbeite mit dem TableSelectionModel
2. Die Farben zu ändern, geht ebenfalls am Problem vorbei.

Wenn du wirklich selektieren willst, dann ist die Methode dafür setRowSelectionInterval(rowIndexFirstRow, rowIndexLastRow).

Hier hab ich auf die schnelle mal einen kurzen Code zusammengezimmert, der berücksichtigt eventuell noch nicht alle Fälle, funktioniert aber grundsätzlich
[CODE lang="java" title="Beispielcode"] public MyFrame() {
//... //
//Das Selektieren der gesamten Zeile erlauben
jTable1.setRowSelectionAllowed(true);
jTable2.setRowSelectionAllowed(true);
//Falls nicht bekannt: Habe hier einen Lambdaaustruck verwendet.
//Hier wird ein ListSelectionListener erzeugt und dem Modell hinzugefügt, der EventParameter e wird ignoriert, da nicht von Belang.
jTable1.getSelectionModel().addListSelectionListener(e -> synchronizeSelection(jTable1, jTable2)); //Index von jTable1 nach jTable2 übertragen
jTable2.getSelectionModel().addListSelectionListener(e -> synchronizeSelection(jTable2, jTable1)); //Index von jTable2 nach jTable1 übertragen
}

/**
* Setzt den RowselectionIndex der Tabelle tSlave auf den Index der ersten markierten Zeile von tMaster.
*/
private void synchronizeSelection(JTable tMaster, JTable tSlave) {
int row1 = tMaster.getSelectedRow();
int row2 = tSlave.getSelectedRow();
// Nur ausführen, wenn sich die Werte unterscheiden, sonst landen wir in einer Endlosschleife.
if (row2 != row1) {
tSlave.setRowSelectionInterval(row1, row1);
}
}
[/CODE]

Super vielen Dank für die Antwort und ich habe es gleich ausprobiert. Funktioniert in einem Demo Projekt aber ich verwende leider einen CellRenderer und bekomme es damit nicht zum laufen 🙁

Hast du mir vielleicht noch einen Tipp?

Danke im Voraus
 
Geht es dir nur um die farbliche Darstellung oder soll die Zeile tatsächlich ausgewählt werden?

Wenn es nur um das Einfärben ohne Änderung der Auswahl geht, dann ist obiges natürlich nicht notwendig.
Dann musst du im Renderer für Tabelle 2 prüfen, ob die entsprechende Zeile in Tabelle 1 selektiert ist.
Der SelectionListener in Tabelle 1 lässt dann einfach nach jeder Auswahl Tabelle 2 neu zeichnen.

Falls es aber doch um die Auswahl geht, dann hast du wahrscheinlich in deinem CellRenderer nicht geprüft, ob die Zelle ausgewählt ist.
Dein Cellrenderer muss natürlich in der Lage sein, eine markierte Zelle anders darzustellen.

Wenn ich CustomRenderer schreibe, hab ich darin auch immer eine Referenz auf den DefaultRenderer.
Zuerst hole ich mir von dem DefaultRenderer das Label, welches bereits korrekt formatiert ist (Farben, Rahmen, Schriftart).
Im Normalfall muss ich dann nur noch den Text austauschen.
Wenn ich hingegen eine Custom-Komponente verwenden will, kopiere ich hingegen Rahmen, Font, Foreground und Background in meine Komponente rein, damit kann man nichts falsch machen.
 
Geht es dir nur um die farbliche Darstellung oder soll die Zeile tatsächlich ausgewählt werden?

Wenn es nur um das Einfärben ohne Änderung der Auswahl geht, dann ist obiges natürlich nicht notwendig.
Dann musst du im Renderer für Tabelle 2 prüfen, ob die entsprechende Zeile in Tabelle 1 selektiert ist.
Der SelectionListener in Tabelle 1 lässt dann einfach nach jeder Auswahl Tabelle 2 neu zeichnen.

Falls es aber doch um die Auswahl geht, dann hast du wahrscheinlich in deinem CellRenderer nicht geprüft, ob die Zelle ausgewählt ist.
Dein Cellrenderer muss natürlich in der Lage sein, eine markierte Zelle anders darzustellen.

Wenn ich CustomRenderer schreibe, hab ich darin auch immer eine Referenz auf den DefaultRenderer.
Zuerst hole ich mir von dem DefaultRenderer das Label, welches bereits korrekt formatiert ist (Farben, Rahmen, Schriftart).
Im Normalfall muss ich dann nur noch den Text austauschen.
Wenn ich hingegen eine Custom-Komponente verwenden will, kopiere ich hingegen Rahmen, Font, Foreground und Background in meine Komponente rein, damit kann man nichts falsch machen.
Im Prinzip habe ich eine Tabelle wo die Zellen unterschiedliche Farben haben können.

Jetzt möchte ich wenn ich auf der linken oder rechten Tabelle eine Zelle markiere die ganze Zeile links und rechts selektieren.

die Farben in den Zellen sollten aber weiterhin dargestellt werden. Geht das?
 
Im Prinzip habe ich eine Tabelle wo die Zellen unterschiedliche Farben haben können.

Jetzt möchte ich wenn ich auf der linken oder rechten Tabelle eine Zelle markiere die ganze Zeile links und rechts selektieren.

die Farben in den Zellen sollten aber weiterhin dargestellt werden. Geht das?
Grundsätzlich geht alles, wenn du weißt, was du willst und es ausformulieren kannst.
Wie Farben "weiterhin" dargestellt werden sollen, weiß ich aber nicht. Was heißt das? Es werden immer irgendwelche Farben dargestellt. Von welchen Farben im Speziellen redest du?
 
Poste mal deinen Renderer (und verwende die Tags zum Posten, im Eingabefenster der Button links oben </>)
klar danke dir

[CODE lang="java" title="Cellrenderer"]import java.awt.Color;
import java.awt.Component;
import java.util.EventObject;

import javax.swing.JComponent;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.border.Border;
import javax.swing.border.LineBorder;
import javax.swing.event.CellEditorListener;
import javax.swing.table.DefaultTableCellRenderer;
import javax.swing.table.TableCellEditor;
import javax.swing.table.TableCellRenderer;



public class CellRenderer extends DefaultTableCellRenderer implements TableCellRenderer {





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


//hier wird noch eine methode aufgerufen zum ermitteln einer farbe
// die Zellen haben unterschiedliche Farben
// vereinfacht hier immer die selbe
comp.setBackground( new Color(255, 153, 153));


setToolTip(table, row, column);


return comp;

}

private void setToolTip(JTable table, int pRow, int pColumn) {
int row = table.convertRowIndexToModel(pRow);
int column = table.convertColumnIndexToModel(pColumn);

setToolTipText((String)table.getModel().getValueAt(row, column));
}


}[/CODE]
 
ok ... du setzt also jedesmal die Hintergrundfarbe manuell auf einen fixen Wert.
Mach das mal abhängig von der Variable "isSelected".
Java:
            if (!isSelected) {
                comp.setBackground(new Color(255, 153, 153));
            }
Entspricht das eher deinen Erwartungen? Falls die Zelle selektiert ist, wird die Standardfarbe für selektierte Zellen verwendet.


Der Tooltip ist übrigens ziemlicher Overkill. Bei jedem Neuzeichnen einer Zelle wird der Toolltip der Tabelle gesetzt, also im Grunde ständig.
Das Setzen des Tooltips sollte nicht im Renderer stattfinden, der soll sich auf's Rendern konzentrieren.

Die Musterlösung wäre das Überschreiben dieser Methode beim Erstellen der Tabelle.

Java:
        jTable2 = new JTable() {
            @Override
            public String getToolTipText(MouseEvent event) {
                JTable table = (JTable) event.getSource();
                Point mousepos = event.getPoint();
                //Hier kommt noch ein Konverter zum Einsatz. Die Spalten können nämlich vertauscht werden, Zeilen gefiltert.
                //Mit convertRowIndexToModel() wird sichergestellt, dass der Wert mit dem Datenmodell übereinstimmt.
                int row = table.convertRowIndexToModel(table.rowAtPoint(mousepos));
                int column = table.convertColumnIndexToModel(table.columnAtPoint(mousepos));
                //Lieber die Werte noch ein letztes Mal prüfen, als eine OutOfBoundsException zu riskieren.
                if (row >= 0 && column >= 0) {
                    return String.valueOf(table.getValueAt(row, column));
                } else {
                    return null;
                }
            }
        };
 
ok ... du setzt also jedesmal die Hintergrundfarbe manuell auf einen fixen Wert.
Mach das mal abhängig von der Variable "isSelected".
Java:
            if (!isSelected) {
                comp.setBackground(new Color(255, 153, 153));
            }
Entspricht das eher deinen Erwartungen? Falls die Zelle selektiert ist, wird die Standardfarbe für selektierte Zellen verwendet.


Der Tooltip ist übrigens ziemlicher Overkill. Bei jedem Neuzeichnen einer Zelle wird der Toolltip der Tabelle gesetzt, also im Grunde ständig.
Das Setzen des Tooltips sollte nicht im Renderer stattfinden, der soll sich auf's Rendern konzentrieren.

Die Musterlösung wäre das Überschreiben dieser Methode beim Erstellen der Tabelle.

Java:
        jTable2 = new JTable() {
            @Override
            public String getToolTipText(MouseEvent event) {
                JTable table = (JTable) event.getSource();
                Point mousepos = event.getPoint();
                //Hier kommt noch ein Konverter zum Einsatz. Die Spalten können nämlich vertauscht werden, Zeilen gefiltert.
                //Mit convertRowIndexToModel() wird sichergestellt, dass der Wert mit dem Datenmodell übereinstimmt.
                int row = table.convertRowIndexToModel(table.rowAtPoint(mousepos));
                int column = table.convertColumnIndexToModel(table.columnAtPoint(mousepos));
                //Lieber die Werte noch ein letztes Mal prüfen, als eine OutOfBoundsException zu riskieren.
                if (row >= 0 && column >= 0) {
                    return String.valueOf(table.getValueAt(row, column));
                } else {
                    return null;
                }
            }
        };
Super danke dir, den Tipp mit dem Tooltip baue ich ein 🙂 und das andere sieht auch besser aus wie mein eigener Ansatz
 
Zuletzt bearbeitet:
ok ... du setzt also jedesmal die Hintergrundfarbe manuell auf einen fixen Wert.
Mach das mal abhängig von der Variable "isSelected".
Java:
            if (!isSelected) {
                comp.setBackground(new Color(255, 153, 153));
            }
Entspricht das eher deinen Erwartungen? Falls die Zelle selektiert ist, wird die Standardfarbe für selektierte Zellen verwendet.


Der Tooltip ist übrigens ziemlicher Overkill. Bei jedem Neuzeichnen einer Zelle wird der Toolltip der Tabelle gesetzt, also im Grunde ständig.
Das Setzen des Tooltips sollte nicht im Renderer stattfinden, der soll sich auf's Rendern konzentrieren.

Die Musterlösung wäre das Überschreiben dieser Methode beim Erstellen der Tabelle.

Java:
        jTable2 = new JTable() {
            @Override
            public String getToolTipText(MouseEvent event) {
                JTable table = (JTable) event.getSource();
                Point mousepos = event.getPoint();
                //Hier kommt noch ein Konverter zum Einsatz. Die Spalten können nämlich vertauscht werden, Zeilen gefiltert.
                //Mit convertRowIndexToModel() wird sichergestellt, dass der Wert mit dem Datenmodell übereinstimmt.
                int row = table.convertRowIndexToModel(table.rowAtPoint(mousepos));
                int column = table.convertColumnIndexToModel(table.columnAtPoint(mousepos));
                //Lieber die Werte noch ein letztes Mal prüfen, als eine OutOfBoundsException zu riskieren.
                if (row >= 0 && column >= 0) {
                    return String.valueOf(table.getValueAt(row, column));
                } else {
                    return null;
                }
            }
        };

1. Vergiss Mouseevents, arbeite mit dem TableSelectionModel
2. Die Farben zu ändern, geht ebenfalls am Problem vorbei.

Wenn du wirklich selektieren willst, dann ist die Methode dafür setRowSelectionInterval(rowIndexFirstRow, rowIndexLastRow).

Hier hab ich auf die schnelle mal einen kurzen Code zusammengezimmert, der berücksichtigt eventuell noch nicht alle Fälle, funktioniert aber grundsätzlich
[CODE lang="java" title="Beispielcode"] public MyFrame() {
//... //
//Das Selektieren der gesamten Zeile erlauben
jTable1.setRowSelectionAllowed(true);
jTable2.setRowSelectionAllowed(true);
//Falls nicht bekannt: Habe hier einen Lambdaaustruck verwendet.
//Hier wird ein ListSelectionListener erzeugt und dem Modell hinzugefügt, der EventParameter e wird ignoriert, da nicht von Belang.
jTable1.getSelectionModel().addListSelectionListener(e -> synchronizeSelection(jTable1, jTable2)); //Index von jTable1 nach jTable2 übertragen
jTable2.getSelectionModel().addListSelectionListener(e -> synchronizeSelection(jTable2, jTable1)); //Index von jTable2 nach jTable1 übertragen
}

/**
* Setzt den RowselectionIndex der Tabelle tSlave auf den Index der ersten markierten Zeile von tMaster.
*/
private void synchronizeSelection(JTable tMaster, JTable tSlave) {
int row1 = tMaster.getSelectedRow();
int row2 = tSlave.getSelectedRow();
// Nur ausführen, wenn sich die Werte unterscheiden, sonst landen wir in einer Endlosschleife.
if (row2 != row1) {
tSlave.setRowSelectionInterval(row1, row1);
}
}
[/CODE]
Hab nochmal eine Frage, mit der Selektion funktioniert echt super und sieht auch gut aus 🙂 Allerdings wenn ich die Spalte sortiere bekomme ich eine Fehlermeldung.

Exception in thread "AWT-EventQueue-0" java.lang.IllegalArgumentException: Row index out of range
at javax.swing.JTable.boundRow(JTable.java:2143)
at javax.swing.JTable.setRowSelectionInterval(JTable.java:2166)

Der Auslöser ist in der Zeile

tSlave.setRowSelectionInterval(row1, row1);

Hast du mir hier noch einen Tipp? Eigentlich muss ich auch nicht die Zeile sortieren

Danke im Voraus 🙂
 

Zurück
Oben