I have searched literally all over the Internet and could not find a working solution to my problem.
I have a JTable, to which I want to dynamically change the background colors of multiple rows without affecting the background color of the other rows which colors might have already been altered.
The color change is triggered by an actionListener on a JMenuItem of a ContextMenu, as shown in the follwowing:
The code that I tried so far is as follows:
JMenu highlightMenu = new JMenu("Highlight");
// Add null
for (Color color : Arrays.asList(Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA,
Color.PINK, Color.GRAY)) {
JMenuItem x = new JMenuItem();
x.setOpaque(true);
x.setBackground(color);
highlightMenu.add(x);
x.addHierarchyListener(e -> x.setText(tab.getTable()
.getValueAt(tab.getTable().getSelectedRow(), tab.getTable().getColumn("Server").getModelIndex()).toString()));
x.addActionListener(e -> IntStream.of(tab.getTable().getSelectedRows())
.forEach(row -> ((Component) tab.getTable().getModel().getValueAt(row, 0)).setBackground(color)));
// x.addActionListener(e -> {
// IntStream.of(tab.getTable().getSelectedRows())
// .forEach(r -> tab.getTable().setDefaultRenderer(Object.class, new
// DefaultTableCellRenderer() {
// @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 (r == row) {
// comp.setBackground(color);
// } else {
// comp.setBackground(null);
// }
// return comp;
// }
// }));
// tab.getTable().repaint();
// });
}
If anyone has a working solution, please share it, would be really appreciated!
EDIT 0: I cleaned-up the edits as they were too numerous, so I added debugging strings and this table is not behaving as it should at all, please see the following screenshot:
Note: Also not sure why but it seems that the table is iterated mutliple times (5) as shown in the above output, this should not be the case as each JMenuItem has its own event listener... And it should be triggered only once depending on which color/JMenuItem is picked...
And the resulting table:
From the following code:
for (Color color : Arrays.asList(Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA,
Color.PINK, Color.GRAY)) {
JMenuItem x = new JMenuItem();
x.setOpaque(true);
x.setBackground(color);
x.setForeground(Color.BLACK);
highlightMenu.add(x);
x.addHierarchyListener(e -> x.setText(tab.getTable()
.getValueAt(tab.getTable().getSelectedRow(), tab.getTable().getColumn("Server").getModelIndex()).toString()));
x.addActionListener(e -> {
IntStream.of(tab.getTable().getSelectedRows()).forEach(row -> this.highlightedRows.put(row, color)
// this.highlightedRows.put(row, Arrays.asList(Color.BLACK, color)
);
tab.getTable().setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
stdOut.println(String.format("%s -> %s", row, highlightedRows.get(row)));
if (highlightedRows.get(row) != null) {
stdOut.println("XXXXXXX");
component.setBackground(highlightedRows.get(row));
}
// if (!isSelected && highlightedRows.containsKey(row)) {
// component.setForeground(highlightedRows.get(row).get(0));
// component.setBackground(highlightedRows.get(row).get(1));
// }
return component;
}
});
});
}
As you see something is not right there...
EDIT N: Almost solved this issue with the following code:
for (Color color : Arrays.asList(Color.RED, Color.ORANGE, Color.YELLOW, Color.GREEN, Color.BLUE, Color.MAGENTA,
Color.PINK, Color.GRAY)) {
final JMenuItem x = new JMenuItem();
x.setOpaque(true);
x.setBackground(color);
x.setForeground(Color.BLACK);
highlightMenu.add(x);
x.addHierarchyListener(e -> x.setText(tab.getTable()
.getValueAt(tab.getTable().getSelectedRow(), tab.getTable().getColumn("Server").getModelIndex()).toString()));
x.addActionListener(e -> {
IntStream.of(tab.getTable().getSelectedRows())
.forEach(row -> this.highlightedRows.put(row, Arrays.asList(Color.BLACK, color)));
// row -> this.highlightedRows.put(row, color)
tab.getTable().setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
final Component component = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row,
column);
stdOut.println(String.format("%s -> %s", row, highlightedRows.get(row)));
if (highlightedRows.containsKey(row)) {
component.setForeground(highlightedRows.get(row).get(0));
component.setBackground(highlightedRows.get(row).get(1));
} else {
if (row % 2 == 0) {
component.setBackground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.background"));
} else {
component
.setBackground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.alternateRowColor"));
}
component.setForeground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.foreground"));
}
if (isSelected) {
component
.setForeground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.selectionForeground"));
component
.setBackground(javax.swing.UIManager.getLookAndFeelDefaults().getColor("Table.selectionBackground"));
}
return component;
}
});
});
}
The only thing now is that the event listener is called more than once, see previous EDIT, whilst this addressed then this would be 100% solved, thanks all!




