JTable单元格渲染器

12

我正在遵循我找到的一些代码(是的,我知道它是如何工作的)。 代码链接在此:Code Link

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

这是我的代码:

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);
    }
}
}

还有单元格渲染器(Cell Renderer)

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;
}
}

问题是,如果我将任何单元格的值设置为“黄色”,它都不会发生变化。

提前致谢!


3
你不应该重写JPanel的paint方法,而应该重写它的paintComponent方法。无论如何,你都不应该在paint或paintComponent中调用程序逻辑。这表明你的代码需要进行全面的修改。 - Hovercraft Full Of Eels
这是因为最终我会让它随着窗口大小而拉伸,所以我需要它更新。 - Diesal11
那不是你拉伸它的方法。再次强调,不要在这些方法中放置代码逻辑。你永远无法完全控制何时甚至是否调用此方法。如果您绝对需要侦听大小调整事件(并且不使用适当的布局管理器),则需要向JPanel添加ComponentListener。 - Hovercraft Full Of Eels
好的,我会记得稍后重新编码。谢谢! - Diesal11
请查看我的答案中的编辑1和2。 - Hovercraft Full Of Eels
应该使用Object.class而不是String.class来调用setDefaultRenderer()。详情请参见此处:http://stackoverflow.com/a/19966915/1128689 - ToFi
3个回答

11

你的渲染器是否被使用了?你将它设置为包含字符串的单元格的默认渲染器,但是你是否重载了模型的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
1
@Diesal:请查看编辑内容,并“请阅读教程”,因为大部分内容都在那里解释了。 - Hovercraft Full Of Eels
1
жҲ‘жҖҖз–‘жңӘи§Ғзҡ„ TableModelеңЁзӣёе…іеҲ—жІЎжңүиҝ”еӣһ String.classгҖӮ - trashgod
1
@trashgod:我同意。我怀疑看不见的“TableModel”对问题提出者也是未知的,并且从未被覆盖。 - Hovercraft Full Of Eels
谢谢!非常抱歉我是一个烦人的新手,我只在Java上开始了大约3周哈哈。 感谢您帮忙整理我的代码。 - Diesal11
显示剩余4条评论

4

添加这一行:

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方法,而且它也不起作用。 - Diesal11
抱歉有点烦人,但它还是不起作用 :/ 您的代码被接受了,但当我改变单元格的值时颜色并没有改变。 - Diesal11
3
DefaultTableCellRendererж╗ўУ«цТЃЁтєхСИІТў»СИЇжђЈТўјуџёсђѓ - trashgod

2

这里有一个简单的解决方案,可以使用 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;
        }
    });

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接