JTable/setDefaultRenderer 多个选定行
JTable/setDefaultRenderer Multiple Selected Rows
我在整个 Internet 上进行了逐字搜索,但找不到解决我问题的有效方法。
我有一个 JTable
,我想动态更改 多行 的背景颜色,而不影响其他颜色可能具有的行的背景颜色已经改了。
颜色变化由ContextMenu
的JMenuItem
上的actionListener
触发,如下图:
目前我试过的代码如下:
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();
// });
}
如果有人有可行的解决方案,请分享,我们将不胜感激!
EDIT 0:我清理了编辑,因为它们太多了,所以我添加了调试字符串,这个 table 根本没有表现得像它应该的那样,请看以下截图:
注意:也不知道为什么,但似乎 table 被迭代了多次 (5),如上面的输出所示,这不应该是这种情况,因为每个 JMenuItem
都有它的自己的事件侦听器...它应该只触发一次,具体取决于选择的 color/JMenuItem...
结果table:
来自以下代码:
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;
}
});
});
}
如你所见,有些地方不对...
编辑 N:几乎用以下代码解决了这个问题:
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;
}
});
});
}
现在唯一的问题是事件侦听器被调用了不止一次,请参阅之前的编辑,同时解决了这个问题,那么这将 100% 解决,谢谢大家!
您可以保留一个将行索引映射到颜色的地图,并在您的默认渲染器中使用它。在动作侦听器中,您只需将具有指定颜色的行索引放入此地图中。
final Map<Integer, Color> highlightedRows = new HashMap<>();
highlightedRows.put(1, Color.GREEN);
highlightedRows.put(2, Color.YELLOW);
table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
final var cmp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
final var color = highlightedRows.get(row);
if (color != null && !isSelected) {
cmp.setBackground(color);
}
return cmp;
}
});
结果
编辑:完全可用的示例
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class TableRowHighlightExample {
private final Map<Integer, Color> highlightedRows = new HashMap<>();
private JTable table;
private JPopupMenu createHighlightMenu() {
final JPopupMenu highlightMenu = new JPopupMenu();
final Color[] colors = {
Color.RED,
Color.ORANGE,
Color.YELLOW,
Color.GREEN,
Color.BLUE,
Color.MAGENTA,
Color.PINK,
Color.GRAY
};
// Add null
for (final Color color : colors) {
final JMenuItem x = new JMenuItem();
x.setOpaque(true);
x.setBackground(color);
highlightMenu.add(x);
x.addActionListener(e -> {
final int[] selectedRows = this.table.getSelectedRows();
for (final int row : selectedRows) {
highlightedRows.put(row, color);
}
});
}
return highlightMenu;
}
private JTable createTable() {
final String[] colNames = { "Column 0" };
final Object[][] data = { { "Row 0" }, { "Row 1" }, { "Row 2" }, { "Row 3" } };
final var table = new JTable(data, colNames);
table.setPreferredSize(new Dimension(500, 200));
table.setComponentPopupMenu(this.createHighlightMenu());
table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
final var cmp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
cmp.setBackground(highlightedRows.get(row));
return cmp;
}
});
return table;
}
public void run() {
final var frame = new JFrame();
this.table = this.createTable();
frame.add(new JScrollPane(this.table));
frame.setSize(500, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) {
new TableRowHighlightExample().run();
}
}
我在整个 Internet 上进行了逐字搜索,但找不到解决我问题的有效方法。
我有一个 JTable
,我想动态更改 多行 的背景颜色,而不影响其他颜色可能具有的行的背景颜色已经改了。
颜色变化由ContextMenu
的JMenuItem
上的actionListener
触发,如下图:
目前我试过的代码如下:
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();
// });
}
如果有人有可行的解决方案,请分享,我们将不胜感激!
EDIT 0:我清理了编辑,因为它们太多了,所以我添加了调试字符串,这个 table 根本没有表现得像它应该的那样,请看以下截图:
注意:也不知道为什么,但似乎 table 被迭代了多次 (5),如上面的输出所示,这不应该是这种情况,因为每个 JMenuItem
都有它的自己的事件侦听器...它应该只触发一次,具体取决于选择的 color/JMenuItem...
结果table:
来自以下代码:
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;
}
});
});
}
如你所见,有些地方不对...
编辑 N:几乎用以下代码解决了这个问题:
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;
}
});
});
}
现在唯一的问题是事件侦听器被调用了不止一次,请参阅之前的编辑,同时解决了这个问题,那么这将 100% 解决,谢谢大家!
您可以保留一个将行索引映射到颜色的地图,并在您的默认渲染器中使用它。在动作侦听器中,您只需将具有指定颜色的行索引放入此地图中。
final Map<Integer, Color> highlightedRows = new HashMap<>();
highlightedRows.put(1, Color.GREEN);
highlightedRows.put(2, Color.YELLOW);
table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
final var cmp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
final var color = highlightedRows.get(row);
if (color != null && !isSelected) {
cmp.setBackground(color);
}
return cmp;
}
});
结果
编辑:完全可用的示例
import java.awt.Color;
import java.awt.Component;
import java.awt.Dimension;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.table.DefaultTableCellRenderer;
public class TableRowHighlightExample {
private final Map<Integer, Color> highlightedRows = new HashMap<>();
private JTable table;
private JPopupMenu createHighlightMenu() {
final JPopupMenu highlightMenu = new JPopupMenu();
final Color[] colors = {
Color.RED,
Color.ORANGE,
Color.YELLOW,
Color.GREEN,
Color.BLUE,
Color.MAGENTA,
Color.PINK,
Color.GRAY
};
// Add null
for (final Color color : colors) {
final JMenuItem x = new JMenuItem();
x.setOpaque(true);
x.setBackground(color);
highlightMenu.add(x);
x.addActionListener(e -> {
final int[] selectedRows = this.table.getSelectedRows();
for (final int row : selectedRows) {
highlightedRows.put(row, color);
}
});
}
return highlightMenu;
}
private JTable createTable() {
final String[] colNames = { "Column 0" };
final Object[][] data = { { "Row 0" }, { "Row 1" }, { "Row 2" }, { "Row 3" } };
final var table = new JTable(data, colNames);
table.setPreferredSize(new Dimension(500, 200));
table.setComponentPopupMenu(this.createHighlightMenu());
table.setDefaultRenderer(Object.class, new DefaultTableCellRenderer() {
@Override
public Component getTableCellRendererComponent(
JTable table, Object value, boolean isSelected,
boolean hasFocus, int row, int column) {
final var cmp = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
cmp.setBackground(highlightedRows.get(row));
return cmp;
}
});
return table;
}
public void run() {
final var frame = new JFrame();
this.table = this.createTable();
frame.add(new JScrollPane(this.table));
frame.setSize(500, 200);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
public static void main(String[] args) {
new TableRowHighlightExample().run();
}
}