每当一个单元格的内容与来自用户的输入匹配时,我想突出显示JTable中的特定行。以下代码是我迄今为止所做的工作:
JTable table = new JTable(model) {
public Component prepareRenderer(
TableCellRenderer renderer, int row,
int column) {
Component c = super.prepareRenderer(renderer,
row, column);
if (!isRowSelected(row) ) {
c.setBackground((hashMapcontainer
.containsKey(row)) ? Color.GREEN
: getBackground());
}
return c;
}
@Override
public boolean isCellEditable(int row, int column) {
return false;
}
};
注意:hashMapcontainer
是一个hashmap
,它是源文件中的全局范围。
现在,这在某种程度上有效,我将此JTable
添加到JTabbedPane
内的JFrame
。 JTable在程序的整个运行时间内动态创建。但是,prepareRenderer
方法会导致所有创建的JTable中的所有特定单元格都被突出显示。
如何让所有JTable中的单元格保留自己特定的突出显示单元格,而不是让所有JTable中的单元格中都有相同的突出显示单元?
提前致谢!
答案 0 :(得分:3)
渲染器是“橡皮图章”。这基本上意味着他们将先前的设置带到下一个单元格。
您需要做的是提供“默认”行为
if (!isRowSelected(row) ) {
c.setBackground((hashMapcontainer
.containsKey(row)) ? Color.GREEN
: getBackground());
} else {
// Define the default background color
// Don't forget to take into the selection state
}
虽然我个人认为prepareRenderer
在这种情况下可能是一个公平的解决方案,但您真的应该探索提供基线渲染器的可能性。这是很多工作要做到正确,但具有可移植的优势(如果您更改表实现)以及允许其他
人们有机会定义给定单元格的突出显示规则,你基本上已经过去了并且被覆盖了,恕我直言。
我还建议您查看JXTable内置的highlighting
答案 1 :(得分:3)
通常,在基本Swing类上重写方法是个坏主意。建议的方法是创建一个Jcomponent
来实现TableCellRenderer
并将其应用于setDefaultRenderer()
的表。请注意,默认情况下,JTable为Object,Number和Boolean类型提供其中的3个。通常,渲染器看起来像这样:
public class MyRenderer extends JLable, implements TableCellRenderer{
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
// Set up default state here
c.setBackground(Color.white);
c.setForeground(Color.black);
// ...
if (!isRowSelected(row) ) {
c.setBackground((hashMapcontainer
.containsKey(row)) ? Color.GREEN
: getBackground());
}
return c;
}
这为您提供了一个可重用的组件,而不是每个创建它的地方都需要扩展JTable。至于在所有表中选择相同的单元格,这是由于isRowSelected
和hashMapContainer
访问全局状态而不是每个实例状态。所有JComponent
都有getClientProperty
和putClientProperty
。这些允许您将自己的状态对象附加到JTable
。然后,您的isRowSelected
变为isRowSelected(table, row)
,只需调用:
MyObject myObj = (MyObject)table.getClientProperty("MySelectionProperty");
myObj.isRowSelected(row);
同样明智的是,hashMapContainer
也可以从表中检索到:
MyHashContainer myHash = (MyHash)table.getClientProperty("MyHashContainer");
<强>更新强>
对于动态生成的表,这几乎是相同的。表创建将如下所示:
JTable t = new JTable();
// other typical table setup, t.setModel(...); etc
t.setDefaultRenderer(String.class, myRenderer);
t.putClientProperty("MySelectionProperty", new MyObject());
t.putClientProperty("MyHashContainer", new MyHashContainer());
值得注意的是,只要渲染器没有状态,就不需要为每个表创建一个实例。我通常会创建一个并将其用于我的所有表格。
以上是对上面渲染器的更新,它不使用全局状态,而是在表格中查找属性:
public class MyRenderer extends JLable, implements TableCellRenderer{
@Override
public Component getTableCellRendererComponent(JTable table, Object value,
boolean isSelected, boolean hasFocus, int row, int column) {
// Pull hashMapContainer from the per-table client properties
MyHashContainer hashMapcontainer = (MyHashContainer)table.getClientProperty("MyHashContainer");
// Set defaults as above
if (!isRowSelected(table, row) ) {
// Same as above
}
return c;
}
// Private method to check for row selection
private boolean isRowSelected(JTable t, int row) {
int[] selectedRows = table.getSelectedRows();
for (int i = 0; i < selectedRows.length; i++) {
if (selectedRows[i] == row) {
return true;
}
}
return false;
}
}
答案 2 :(得分:0)
我希望我的 JTable 使用高亮颜色显示更新的行,以便轻松查看正在更新的行。这就是我完成它的方式。该解决方案是作为传统 TableCellRenderer 的包装器实现的。像这样使用它:
RowHighlighter highlighter = new RowHighlighter(table);
table.setDefaultRenderer(Date.class, highlighter.wrap(new DefaultTableCellRenderer()));
STEPS 和 PERIOD 允许配置(我猜应该是一个参数)高光如何淡入背景。在本例中,它将在 2 秒内通过 50 步淡出到单元格的背景颜色。这也保留了真实渲染器的背景颜色,包括当前是否选择了行。
import java.awt.Color;
import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.swing.JTable;
import javax.swing.Timer;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.TableCellRenderer;
class RowHighlighter implements TableModelListener, ActionListener {
private static int STEPS = 50;
private static int PERIOD = 2000;
private Map<Integer, Integer> rowHighlights = new HashMap<>();
private JTable table;
public RowHighlighter(JTable table) {
this.table = table;
table.getModel().addTableModelListener(this);
Timer timer = new Timer(PERIOD/STEPS, this);
timer.start();
}
@Override
public void tableChanged(TableModelEvent e) {
int first = e.getFirstRow();
int last = e.getLastRow();
for (int i=first; i<=last; i++) {
rowHighlights.put(i, STEPS);
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (rowHighlights.size() == 0)
return;
Iterator<Map.Entry<Integer, Integer>> it = rowHighlights.entrySet().iterator();
while (it.hasNext()) {
Map.Entry<Integer, Integer> entry = it.next();
int v = entry.getValue();
if (v > 1) {
entry.setValue(v - 1);
} else {
it.remove();
}
}
table.repaint();
}
public TableCellRenderer wrap(TableCellRenderer delegate) {
return new HighlightingTableCellRenderer(rowHighlights, delegate);
}
private static class HighlightingTableCellRenderer implements TableCellRenderer {
private Map<Integer, Integer> rowMap;
private TableCellRenderer delegate;
public HighlightingTableCellRenderer(Map<Integer, Integer> rowMap, TableCellRenderer delegate) {
this.rowMap = rowMap;
this.delegate = delegate;
}
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
int row, int column) {
Component c = delegate.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
Integer v = rowMap.get(row);
if (v != null) {
Color background = c.getBackground();
Color highlight = getColor(v, Color.PINK, background);
c.setBackground(highlight);
}
return c;
}
private Color getColor(int n, Color from, Color to) {
float p = ((float)n)/STEPS;
return new Color((int)(from.getRed() * p + to.getRed() * (1-p)),
(int)(from.getGreen() * p + to.getGreen() * (1-p)),
(int)(from.getBlue() * p + to.getBlue() * (1-p)));
}
}
}