Updating/Calling JTable rendering when a value is changed MANUALLY/DYNAMICALLY

Tags: , ,



so i want my JTable to render everytime a value in a variable is changed however this is not taking place, the table is only getting rendered either when I click on it, or move it out of view then back in. Any suggestions? I am using a custom TableCellRender as posted below.

import java.awt.Color;
import java.awt.Component;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.TableCellRenderer;

public class myRenderer extends JLabel implements TableCellRenderer {

   private static final long serialVersionUID = 1L;

   public myRenderer()
   {
       super.setOpaque(true);
   }

   @Override
   public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
           int row, int column) {
       setHorizontalAlignment(SwingConstants.CENTER);
       setText(value.toString());
       Color myColor = new Color(255, 253, 117);
       setBackground(myColor);
       if(value == Integer.valueOf(-1))
       {
           value = null;
           setText("");
           return this;
       } 
       for(int i = 0; i < 90; i++) {
           if(value == Integer.valueOf(finalClass.done[i])) //this value changes during the program.
           {
               setBackground(Color.cyan); 
           }
       }
       return this;
   }

}

I want my table to render everytime that the value in finalClass.done is changed in any other part of the program. any ideas? i tried the revalidate option, but got no results.

EDIT: Here is a minimal version of finalClass, which when run together with the above mentioned renderer code, can reproduce the same error I’m facing.

import javax.swing.JFrame;
import javax.swing.JTable;
import javax.swing.table.DefaultTableModel;

public class finalClass {
    JFrame frame = new JFrame();
    static int[] done = new int[90];
    Integer[][] slip = new Integer[9][5];
    String colHeader[] = {"1","2","3","4","5"};
    JTable table;
    finalClass() {
        for(int i = 0; i<90; i++)
            done[i] = -1;
        int cnt = 0;
        for(int x = 0; x<9; x++ ) {
            for(int y = 0; y <5; y++) {
                slip[x][y] = cnt++;
            }
        }
        DefaultTableModel tableModel = new DefaultTableModel(slip, colHeader) {
            private static final long serialVersionUID = 1L;
            @Override
            public boolean isCellEditable(int row, int column) {
               //all cells false
               return false;
            }
        };
        table = new JTable(slip, colHeader);
        table.setDefaultRenderer(Object.class, new myRenderer());
        table.setModel(tableModel);
        frame.add(table);
        frame.setVisible(true);
        frame.pack();

    }
    public static void main(String[] args) {
        new finalClass();
        try {
        Thread.sleep(5000);
        done[5] = 10; 
        } catch(Exception e) {
            e.printStackTrace();
        }
    }
}

Thank you all in advance for bearing with me. I’m new here so it might take a little time for me to understand how things are done around here. sorry to waste your time and thanks for the help in advance.

Answer

The reason why the value shows only after you move the table or click on it, is that by doing so you force a repaint.
You can verify it by invoking frame.repaint() after done[5] = 10;

The following is a one-file MRE (copy paste the entire code into FinalClass.java and run):

import java.awt.Color;
import java.awt.Component;
import java.util.Arrays;    
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingConstants;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableCellRenderer;

public class FinalClass {

    private final JFrame frame = new JFrame();
    private final int[] done = new int[90]; //better avoid static
    private final Integer[][] slip = new Integer[9][5];
    private final String colHeader[] = {"1","2","3","4","5"};
    private JTable table;

    FinalClass() {

        Arrays.fill(done, -1);
        int cnt = 0;
        for(int x = 0; x<9; x++ ) {
            for(int y = 0; y <5; y++) {
                slip[x][y] = cnt++;
            }
        }

        DefaultTableModel tableModel = new DefaultTableModel(slip, colHeader) {
            private static final long serialVersionUID = 1L;
            @Override
            public boolean isCellEditable(int row, int column) {
               //all cells false
               return false;
            }
        };

        table = new JTable(slip, colHeader);
        table.setDefaultRenderer(Object.class, new MyRenderer());
        table.setModel(tableModel);
        frame.add(table);
        frame.pack();
        frame.setVisible(true);
    }

    private void refresh(){
        frame.repaint();
    }

    void done(int index, int value){
        done[index] = value;
        refresh();
    }

    public static void main(String[] args) {

        FinalClass f = new FinalClass();
        try {
            Thread.sleep(3000);
            f.done(5, 10);
        } catch(Exception e) { e.printStackTrace(); }
    }

    //follow java naming conventions
    class MyRenderer extends JLabel implements TableCellRenderer {

           private static final long serialVersionUID = 1L;

           public MyRenderer()
           {
               super.setOpaque(true);
           }

           @Override
           public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus,
                   int row, int column) {
               setHorizontalAlignment(SwingConstants.CENTER);
               setText(value.toString());
               Color myColor = new Color(255, 253, 117);
               setBackground(myColor);
               if((int)value == -1)
               {
                   value = null;
                   setText("");
                   return this;
               }
               for(int i = 0; i < 90; i++) {
                   if((int)value == done[i]) //this value changes during the program.
                   {
                       setBackground(Color.cyan);
                   }
               }
               return this;
           }
        }
}


Side notes:
1. If you want the table to respond automatically to change in the undelying data, you need to apply the change to its model as demonstrated in this answer to your previous question.

2.Modifying done from more than one thread needs to be synchronized.
3.It is recommended to follow Java Naming Conventions



Source: stackoverflow