12

I'm following some code I found, (Yes I understand how it works) It's from here :Code Link

What i'm trying to do is set a cells Foreground color if the cells value is set to "yellow"

Here is my Code:

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

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

The problem is it isn't changing, if I set any cells value to "yellow"

Thanks in advance!

Heisenbug
  • 38,762
  • 28
  • 132
  • 190
Diesal11
  • 3,389
  • 9
  • 28
  • 29
  • 3
    You shouldn't be overriding JPanel's paint method but rather its paintComponent method, and regardless of this, you should never have program logic being called from within paint or paintComponent. This suggests that your code needs to be over-hauled. – Hovercraft Full Of Eels Jul 11 '11 at 01:33
  • This is in there because eventually i'm going to make it stretch with the window size, so I need it to update. – Diesal11 Jul 11 '11 at 01:35
  • that's not how you make it stretch. Again, never put code logic in these methods. You never have full control over when or even if this method is called. If you absolutely need to listen to a resize event (and are not using an appropriate layout manager), then you need to add a ComponentListener to the JPanel. – Hovercraft Full Of Eels Jul 11 '11 at 01:37
  • Ok, ill remember to recode that later. Thanks! – Diesal11 Jul 11 '11 at 01:39
  • Please see edits 1 and 2 in my answer. – Hovercraft Full Of Eels Jul 11 '11 at 02:01
  • `setDefaultRenderer()` should be invoked with `Object.class` instead of `String.class`. See here for Details: http://stackoverflow.com/a/19966915/1128689 – ToFi Dec 13 '13 at 18:08

3 Answers3

11

Is your renderer ever even used? You make it the default renderer for cells containing String, but have you overloaded your model's getColumnClass method so that it knows that some of the cells hold Strings?

So first I'd use println statements to see if the renderer is even being called and if not, I'd override my model's method as noted above.

Edit 1
Also your if results are bound to be strange. In the if portion you change the forground and in the else you change the background -- makes no sense. You probably should do complementary changes in state in the if vs. the else blocks, not orthogonal changes.

Edit 2
For example:

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;
   }
}
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373
  • isn't that what this line does:`table.setDefaultRenderer(String.class, new BoardTableCellRenderer());` – Diesal11 Jul 11 '11 at 01:52
  • @Diesal11: no, not at all. it only sets the renderer for String objects, but the model has no way of knowing what is a String cell unless you *specifically tell it so*, which is why you need to extend the model, usually a DefaultTableModel. – Hovercraft Full Of Eels Jul 11 '11 at 01:56
  • Sorry, i made that fix right after i posted the question, and forgot to change it – Diesal11 Jul 11 '11 at 01:56
  • Ahh ok, sorry to be annoying but briefly how would I do that? – Diesal11 Jul 11 '11 at 02:00
  • 1
    @Diesal: see edits, and *please read the tutorial as most of this is in there*. – Hovercraft Full Of Eels Jul 11 '11 at 02:01
  • 1
    I suspect the unseen `TableModel` is not returning `String.class` for the relevant column. – trashgod Jul 11 '11 at 02:01
  • 1
    @trashgod: I agree. I suspect that the unseen `TableModel` remains unseen to the OP as well and has never been overridden. – Hovercraft Full Of Eels Jul 11 '11 at 02:02
  • THANKYOU! I'm so sorry to be such an annoying noob, I only started on java about 3 weeks ago haha. Thanks for cleaning up my code a little too. – Diesal11 Jul 11 '11 at 02:16
  • man, you just saved my day with edit2. I spent a lot of time but only this solved my problem (BoardTableCellRenderer class, to change a "cell" color like YES>GREEN and NO>RED). – TroniPM Jul 25 '18 at 18:34
4

Add this line:

c.setOpaque(true);

The Component returned by getTableCellRendererComponent must be opaque in order to see changes on background and foreground color. The problem here is also another: you are extending DefaultTableCellRenderer (that is a JComponent) but you are returning a Component that hasn't setOpaque method. I would refactor your code like this:

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;
}
Heisenbug
  • 38,762
  • 28
  • 132
  • 190
2

Here is a simple solution, use TableCellRenderer as an inner class.

    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;
        }
    });
user1069816
  • 2,763
  • 2
  • 26
  • 43
Syed Maruf
  • 21
  • 1