如何在JTable中设置满足特定条件的文本颜色?低于40分文本变红却全部变红的问题排查
问题分析与解决方案
嗨,这问题我一眼就看出来啦!你之所以会出现所有文本都变红的情况,核心原因是你在循环里修改的是整个JTable的前景色,而不是单个单元格/行的颜色。
错误原因拆解
你写的这段循环代码:
for (int i = 0; i < tb1.getRowCount(); i++) { Object x = tb1.getValueAt(i, 1); String y = x.toString(); double z = Double.parseDouble(y); if (z < 40) { tb1.setForeground(Color.RED); } else { tb1.setForeground(new Color(38, 120, 81)); } }
每次循环都会给整个tb1(也就是整个表格)设置前景色,循环最后一次执行的是第二行(Amy的30分),此时触发tb1.setForeground(Color.RED),所以整个表格的文字都变成红色了——前面的设置全被最后一次覆盖掉了。
正确的解决方法:使用TableCellRenderer
要实现单个单元格/行的颜色自定义,我们需要使用TableCellRenderer(表格单元格渲染器),它能让我们对每个单元格的显示样式单独控制。
下面是修改后的完整代码,我替换了原来的循环部分,改用自定义渲染器:
import java.awt.*; import javax.swing.*; import javax.swing.table.*; public class testing{ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { mark(); } }); } public static void mark() { String[] columns = new String[] {"Name", "Marks(%)"}; Object[][] data= new Object[][] { {"Aby", "100"}, {"Amy", "30"} }; JFrame frame = new JFrame("Student Marks List"); frame.setVisible(true); frame.setSize(600, 500); frame.setLayout(new BorderLayout()); Panel details = new Panel(null); details.setBounds(0,50, 1000, 125); Panel contents = new Panel(null); contents.setBounds(0,50, 1000, 600); frame.add(details, BorderLayout.NORTH); frame.add(contents, BorderLayout.CENTER); JTable tb1; tb1 = new JTable(data, columns); JScrollPane sp = new JScrollPane(tb1); tb1.getTableHeader().setOpaque(false); tb1.getTableHeader().setFont(new Font("Barlow Condensed ExtraBold", Font.BOLD, 20)); tb1.getTableHeader().setPreferredSize(new Dimension(100, 30)); tb1.setFont(new Font("Barlow Condensed", Font.BOLD, 20)); tb1.setRowHeight(30); // 自定义单元格渲染器,替代原来的循环 DefaultTableCellRenderer markRenderer = new DefaultTableCellRenderer(){ @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { // 先调用父类方法获取默认渲染组件 Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); // 只针对Marks列(索引1)进行颜色设置 if(column == 1){ try{ double mark = Double.parseDouble(value.toString()); if(mark < 40){ c.setForeground(Color.RED); }else{ c.setForeground(new Color(38, 120, 81)); } }catch(NumberFormatException e){ // 如果值不是数字,用默认颜色 c.setForeground(table.getForeground()); } }else{ // 其他列用默认颜色 c.setForeground(table.getForeground()); } // 设置居中对齐(把你原来的centerRenderer功能整合进来了) setHorizontalAlignment(JLabel.CENTER); return c; } }; // 把渲染器应用到Marks列 tb1.getColumnModel().getColumn(1).setCellRenderer(markRenderer); // 其他列也设置居中对齐 DefaultTableCellRenderer centerRenderer = new DefaultTableCellRenderer(); centerRenderer.setHorizontalAlignment(JLabel.CENTER); tb1.getColumnModel().getColumn(0).setCellRenderer(centerRenderer); tb1.setBounds(25,10,200,375); sp.setBounds(25,10,200,375); contents.add(sp); } }
代码关键点说明
- 我们继承
DefaultTableCellRenderer并重写getTableCellRendererComponent方法,这个方法会为每个单元格返回渲染组件,所以能单独控制每个单元格的样式。 - 只针对第二列(
column == 1)进行分数判断,其他列保持默认样式。 - 加入了异常处理,防止单元格值不是数字时出错。
- 把你原来的居中对齐需求也整合到了渲染器里,让代码更简洁。
这样修改后,只有低于40分的单元格文字会变成红色,其他分数和姓名列都会显示你设置的绿色啦~
内容的提问来源于stack exchange,提问作者Lynn




