我有一个JTable,我希望我能够更改单击的单个单元格的颜色。
以下是我的代码的简化版本:
public class TableFrame extends JFrame {
public TableFrame() {
JTable table = new JTable(8, 8);
table.setGridColor(Color.BLACK);
table.setDefaultRenderer(CustomCellRenderer.class, new CustomCellRenderer());
getContentPane().add(table);
}
public class CustomCellRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (hasFocus) {
l.setBackground(Color.red);
l.setText("Hello");
}
return l;
}
}
}
当我点击某个单元格时,我希望它将颜色更改为红色并添加“Hello”。它改变了文本,但出于某些奇怪的原因,它会改变所有单元格的颜色吗?当我点击一个未着色的单元格时,它会做同样的事情,但如果有意义的话,并不总是以有条理的方式进行?比如,它不会为它之后的所有细胞着色,但也许有些只是在上面并且让其他人留空......
这真的很奇怪,没有任何意义。发生了什么事?
答案 0 :(得分:3)
稍微挖了DefaultTableCellRenderer
类,当你在支持setBackground
的{{1}}组件上调用JLabel
时,它会存储你使用的值...
DefaultTableCellRenderer
当再次绘制单元格时,它是用于重新绘制单元格的值(public void setBackground(Color c) {
super.setBackground(c);
unselectedBackground = c;
}
),默认为"模式...
unselectedBackground
这意味着,当您使用 if (isSelected) {
//...
} else {
Color background = unselectedBackground != null
? unselectedBackground
: table.getBackground();
if (background == null || background instanceof javax.swing.plaf.UIResource) {
Color alternateColor = DefaultLookup.getColor(this, ui, "Table.alternateRowColor");
if (alternateColor != null && row % 2 != 0) {
background = alternateColor;
}
}
super.setForeground(unselectedForeground != null
? unselectedForeground
: table.getForeground());
super.setBackground(background);
}
并将其传递给setBackground
时,Color.RED
会假定这成为所有未选定单元格的默认颜色。
您唯一的选择是手动重置背景颜色,例如......
DefaultTableCellRenderer
另外,你应该使用更像......的东西。
public class CustomCellRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (hasFocus) {
l.setBackground(Color.red);
l.setText("Hello");
} else if (!isSelected) {
l.setBackground(table.getBackground());
}
return l;
}
}
注册单元格渲染器,因为它是由table.setDefaultRenderer(Object.class, new CustomCellRenderer());
返回的Class
类型,用于确定使用哪个单元格渲染器;)
答案 1 :(得分:1)
由于OP只需要渲染的帮助而不需要数据...这里有(假设有一个名为hasBeenClicked(row,column)
的函数可用于确定单元格是否已被访问尚未。
public class CustomCellRenderer extends DefaultTableCellRenderer {
@Override
public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) {
JLabel l = (JLabel) super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
if (hasBeenClicked(row,column)) {
l.setBackground(Color.red);
l.setText("Hello");
} else {
// reset the label to white background
l.setBackground(Color.white);
l.setText("Hello");
}
return l;
}
}
}
另请注意,渲染器的注册应为
table.setDefaultRenderer(Object.class, new CustomCellRenderer());
由于我们希望所有列都具有此渲染器(渲染器是针对模型中列的类注册的)。
我使用以下hasBeenClicked
方法进行了测试。
public boolean hasBeenClicked(int row, int column){
return (row%2==0 && column%2==0);
}
只需实现自己跟踪是否已点击某个单元格,您应该好好去。请记住,您不应该使用渲染器来跟踪点击次数,而是使用某种类型的侦听器。