JTable 单元格渲染器

Posted

技术标签:

【中文标题】JTable 单元格渲染器【英文标题】:JTable Cell Renderer 【发布时间】:2011-10-02 11:05:10 【问题描述】:

我正在关注我找到的一些代码,(是的,我了解它是如何工作的) 来自这里:Code Link

如果单元格值设置为“黄色”,我要做的是设置单元格的前景色

这是我的代码:

public class Board extends JPanel

private static final long serialVersionUID = 1L;

int boardHeight = 20;
int boardWidth = 10;

JTable table;

public Board() 
    table = new JTable(this.boardHeight, this.boardWidth);
    table.setDefaultRenderer(String.class, new BoardTableCellRenderer());
    table.setFocusable(false);
    table.setShowGrid(false);
    table.setRowMargin(0);
    table.setIntercellSpacing(new Dimension(0,0));
    table.setRowSelectionAllowed(false);
    table.setVisible(true);
    this.add(table);
    this.setPreferredSize(new Dimension(table.getPreferredSize().width, (table.getPreferredSize().height + 85)));


public void paint(Graphics g) 
    table.setRowHeight(20);
    for (int x = 0; x < this.table.getColumnCount(); ++x) 
        TableColumn col = this.table.getColumnModel().getColumn(x);
        col.setPreferredWidth(20);
    


还有细胞渲染器

public class BoardTableCellRenderer extends DefaultTableCellRenderer 

private static final long serialVersionUID = 1L;

public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,int row,int col) 

    Component c = super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, col);
    String s = table.getModel().getValueAt(row, col).toString();

    if (s.equalsIgnoreCase("yellow")) 
        c.setForeground(Color.YELLOW);
    
    else 
        c.setForeground(Color.WHITE);
    

    return c;


问题是它没有改变,如果我将任何单元格值设置为“黄色”

提前致谢!

【问题讨论】:

你不应该重写 JPanel 的paint 方法,而应该重写它的paintComponent 方法,不管怎样,你不应该从paint 或paintComponent 中调用程序逻辑。这表明您的代码需要大修。 这是因为最终我要让它随着窗口大小而拉伸,所以我需要更新它。 这不是你让它伸展的方式。同样,永远不要将代码逻辑放在这些方法中。您永远无法完全控制何时甚至是否调用此方法。如果您绝对需要监听调整大小事件(并且没有使用适当的布局管理器),那么您需要将 ComponentListener 添加到 JPanel。 好的,记得稍后重新编码。谢谢! 请在我的回答中查看编辑 1 和 2。 【参考方案1】:

您的渲染器是否曾经使用过?您将其设置为包含字符串的单元格的默认渲染器,但是您是否重载了模型的 getColumnClass 方法,以便它知道某些单元格包含字符串?

所以首先我会使用 println 语句来查看渲染器是否被调用,如果没有,我会覆盖我的模型的方法,如上所述。

编辑 1 你的 if 结果也一定很奇怪。在 if 部分更改前景,在 else 更改背景 - 没有意义。您可能应该在 if 与 else 块中对状态进行互补更改,而不是正交更改。

编辑 2 例如:

import java.awt.*;
import java.util.Random;

import javax.swing.*;
import javax.swing.table.*;

public class Board extends JPanel 

   private static final long serialVersionUID = 1L;

   int boardHeight = 20;
   int boardWidth = 10;

   JTable table;
   Random random = new Random();

   public Board() 
      setLayout(new BorderLayout()); // !!
      DefaultTableModel model = new DefaultTableModel(boardHeight, boardWidth) 
         @Override
         public Class<?> getColumnClass(int columnIndex) 
            return String.class;
         
      ;
      // !! table = new JTable(this.boardHeight, this.boardWidth);
      table = new JTable(model);
      for (int row = 0; row < model.getRowCount(); row++) 
         for (int col = 0; col < model.getColumnCount(); col++) 
            String s = random.nextBoolean() ? "red" : "yellow";
            model.setValueAt(s, row, col);
         
      
      table.setDefaultRenderer(String.class, new BoardTableCellRenderer());

      table.setFocusable(false);
      table.setShowGrid(false);
      table.setRowMargin(0);
      table.setIntercellSpacing(new Dimension(0, 0));
      table.setRowSelectionAllowed(false);
      table.setVisible(true);
      this.add(table);
      this.setPreferredSize(new Dimension(table.getPreferredSize().width,
               (table.getPreferredSize().height + 85)));
   

   private static void createAndShowUI() 
      JFrame frame = new JFrame("Board");
      frame.getContentPane().add(new Board());
      frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
      frame.pack();
      frame.setLocationRelativeTo(null);
      frame.setVisible(true);
   

   public static void main(String[] args) 
      java.awt.EventQueue.invokeLater(new Runnable() 
         public void run() 
            createAndShowUI();
         
      );
   


class BoardTableCellRenderer extends DefaultTableCellRenderer 

   private static final long serialVersionUID = 1L;

   public Component getTableCellRendererComponent(JTable table, Object value,
            boolean isSelected, boolean hasFocus, int row, int col) 

      Component c = super.getTableCellRendererComponent(table, value,
               isSelected, hasFocus, row, col);
      Object valueAt = table.getModel().getValueAt(row, col);
      String s = "";
      if (valueAt != null) 
         s = valueAt.toString();
      

      if (s.equalsIgnoreCase("yellow")) 
         c.setForeground(Color.YELLOW);
         c.setBackground(Color.gray);
       else 
         c.setForeground(Color.black);
         c.setBackground(Color.WHITE);
      

      return c;
   

【讨论】:

这行不就是这样吗:table.setDefaultRenderer(String.class, new BoardTableCellRenderer()); @Diesal11:不,一点也不。它只为 String 对象设置渲染器,但模型无法知道什么是 String 单元格,除非您明确告诉它,这就是为什么您需要扩展模型,通常是 DefaultTableModel。 @Diesal:查看编辑,请阅读教程,因为其中大部分内容都在其中 我怀疑看不见的TableModel 没有返回相关列的String.class @trashgod:我同意。我怀疑看不见的 TableModel 对 OP 来说仍然是看不见的,并且从未被覆盖。【参考方案2】:

添加这一行:

c.setOpaque(true);

getTableCellRendererComponent 返回的组件必须是不透明的,才能看到背景和前景色的变化。 这里的问题也是另一个问题:您正在扩展 DefaultTableCellRenderer(即 JComponent),但您正在返回一个没有 setOpaque 方法的组件。我会像这样重构你的代码:

public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,int row,int col) 

    String s = table.getModel().getValueAt(row, col).toString();
    this.setOpaque(true);
    if (s.equalsIgnoreCase("yellow")) 
        this.setForeground(Color.YELLOW);
    
    else 
        this.setBackground(Color.WHITE);
    

    return this;

【讨论】:

Eclipse 告诉我它没有 SetOpaque 方法。它也不起作用。 抱歉打扰了,但它仍然无法正常工作:/ 您的代码已被接受,但当我更改单元格值时颜色没有改变。 DefaultTableCellRenderer 默认是不透明的。【参考方案3】:

这里有一个简单的解决方案,使用 TableCellRenderer 作为内部类。

    myTable.setDefaultRenderer(Object.class, new TableCellRenderer()
    
        JLabel comp = new JLabel();
        String val;

        @Override
        public Component getTableCellRendererComponent(
                             JTable table, 
                             Object value, 
                             boolean isSelected, 
                             boolean hasFocus, 
                             int row, 
                             int column)
        
            comp.setOpaque(true);
            comp.setForeground(Color.BLACK); // text color

            if (value != null)
            
                val = value.toString();
                comp.setText(val);

                if (val.equalsIgnoreCase("red"))
                
                    comp.setBackground(Color.RED);
                
                else if (val.equalsIgnoreCase("yellow"))
                
                    comp.setBackground(Color.YELLOW);
                
                else if (val.equalsIgnoreCase("green"))
                
                    comp.setBackground(Color.GREEN);
                
                else
                
                    comp.setBackground(Color.WHITE);
                
            
            return comp;
        
    );

【讨论】:

以上是关于JTable 单元格渲染器的主要内容,如果未能解决你的问题,请参考以下文章

JTable 的单元格渲染器 - 彩色行

通过自定义单元格渲染器在Jtable中显示超链接

JTable 自定义单元格渲染器焦点问题

jTable 单元格背景颜色

Swing-JTable的渲染器与编辑器使用demo

为啥我的 JTable CellRenderer 一直在运行?