2

I have a timer class updating my table but the only way I have found to affect a change is to use this code. It is essentially a break time application. I am using ini4j to read an ini file on the network. It does work but it's creating speed issues with other things I am doing. With the current setup it shows the times more or less correctly but start to lag when I add more people. If you answer is learn jTables that's not going to be helpful lol. I havn't been able to get this to work using jtables and fireupdate changes.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.TimeZone;

import javax.swing.JLabel;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

import main.Break;

import org.ini4j.InvalidFileFormatException;
import org.ini4j.Wini;

public class TableUpdate extends JLabel implements ActionListener {

    /**
     * 
     */
    private static final long serialVersionUID = 4357754555235469274L;
    private volatile static boolean running = true;
    SimpleDateFormat UTC = new SimpleDateFormat("HH:mm:ss");    
    Timer breaktimer = new Timer(1000, this);   
    public static long now = System.currentTimeMillis();

    final static String local = ConfigIni.location();
    final static File FILENAME = new File(local+"\\master.ini");

    @Override
    public void actionPerformed(ActionEvent arg0) {
        Runnable runnable = new Runnable() {
             public void run() {

                    tableupdate();  
             }};
            SwingUtilities.invokeLater(runnable);
        }

    public void tableupdate() {  
        UTC.setTimeZone(TimeZone.getTimeZone("UTC"));          
            Wini ini = null;
            try {
                ini = new Wini(FILENAME);
            } catch (InvalidFileFormatException e1) {               
                e1.printStackTrace();
            } catch (IOException e1) {              
                e1.printStackTrace();
            }
            String number = ini.get("analysts", "number");

            if (number.equals("8")) {
                Break.jTable1.setModel(new javax.swing.table.DefaultTableModel(
                 new Object [][] {
                 {AnalystIni.one(), StartIni.one(), BreakIni.one(), TypeIni.one()},
                 {AnalystIni.two(), StartIni.two(), BreakIni.two(), TypeIni.two()},
                 {AnalystIni.three(), StartIni.three(), BreakIni.three(), TypeIni.three()},
                 {AnalystIni.four(), StartIni.four(), BreakIni.four(), TypeIni.four()},
                 {AnalystIni.five(), StartIni.five(), BreakIni.five(), TypeIni.five()},
                 {AnalystIni.six(), StartIni.six(), BreakIni.six(), TypeIni.six()},
                 {AnalystIni.seven(), StartIni.seven(), BreakIni.seven(), TypeIni.seven()},
                 {AnalystIni.eight(), StartIni.eight(), BreakIni.eight(), TypeIni.eight()},              
                         },
                         new String [] {
                         "Analyst", "Start Time", "Timer", "Status"
                         }
                     ));


            }
    }

    public void start()  {

        running = true;
        breaktimer.start();
    }

    public void stop() {

        running = false;
    }

    public static void main(String[] args) {    

        java.awt.EventQueue.invokeLater(new Runnable() {
        public void run() {         
            TableUpdate jtl = new TableUpdate();
            jtl.start();
            }
    });                    
    }
}

Here is the code for my table

try {
            jTable1.setModel(new javax.swing.table.DefaultTableModel(

                new Object [][] {
                    {AnalystIni.one(), StartIni.one(), BreakIni.one(), TypeIni.one()},
                    {AnalystIni.two(), StartIni.two(), BreakIni.two(), TypeIni.two()},
                    {AnalystIni.three(), StartIni.three(), BreakIni.three(), TypeIni.three()},
                    {AnalystIni.four(), StartIni.four(), BreakIni.four(), TypeIni.four()},
                    {AnalystIni.five(), StartIni.five(), BreakIni.five(), TypeIni.five()},
                    {AnalystIni.six(), StartIni.six(), BreakIni.six(), TypeIni.six()},
                    {AnalystIni.seven(), StartIni.seven(), BreakIni.seven(), TypeIni.seven()},
                    {AnalystIni.eight(), StartIni.eight(), BreakIni.eight(), TypeIni.eight()}
                },
                new String [] {
                    "Analyst", "Time Started", "Timer", "Status"
                }
            ));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        JTableHeader header = jTable1.getTableHeader();
        header.setBackground(SettingsIni.jtable1h());
        header.setForeground(SettingsIni.jtable1ht());
        jTable1.setBackground(SettingsIni.jtable1());
        jTable1.setForeground(SettingsIni.jtable1t());
        jTable1.setOpaque(false);
        jScrollPane1.setViewportView(jTable1);
        jScrollPane1.setOpaque(false);
        jTable1.setFocusable(false);
        //jScrollPane1.setBorder(BorderFactory.createMatteBorder(0,1,0,0,Color.black));
        jScrollPane1.setBorder(BorderFactory.createEmptyBorder(0,0,0,0));

        jScrollPane1.getViewport().setOpaque(false);
        final Color jcolor1 = new Color(0, true);
        jScrollPane1.getViewport().setBackground(jcolor1);

        getRootPane().setBorder(BorderFactory.createEmptyBorder(0,0,0,0));//removed border

I have added this code to the class with the table.

@Override
    public void tableChanged(TableModelEvent e) {
        int row = e.getFirstRow();
        int column = e.getColumn();
        TableModel model = (TableModel)e.getSource();
        String columnName = model.getColumnName(column);
        Object data = model.getValueAt(row, column);        
    }

And I am looking at adding this to my timer, but it still feels like I am missing something.

BreakTimev21.jTable1.tableChanged(new TableModelEvent(BreakTimev21.jTable1.getModel()));

From camickr I tried this in my tableupdate class. Still didn't help, it does update but is kinda glitchy. I did remember to use jTable1.setAutoCreateColumnsFromModel(false);

Object [][] data = {
                        {a1, StartIni2.one(), BreakIni2.one(), TypeIni2.one()},
                        {a2, StartIni2.two(), BreakIni2.two(), TypeIni2.two()},
                        {a3, StartIni2.three(), BreakIni2.three(), TypeIni2.three()},
                        {a4, StartIni2.four(), BreakIni2.four(), TypeIni2.four()},
                        {a5, StartIni2.five(), BreakIni2.five(), TypeIni2.five()},
                        {a6, StartIni2.six(), BreakIni2.six(), TypeIni2.six()},
                        {a7, StartIni2.seven(), BreakIni2.seven(), TypeIni2.seven()},
                        {a8, StartIni2.eight(), BreakIni2.eight(), TypeIni2.eight()},
                    };
                    String [] columnNames = {
                        "Analyst", "Start Time", "Timer", "Status"
                    };

                    TableModel model = BreakTimev21.jTable1.getModel();
                    ((DefaultTableModel) model).setDataVector(data, columnNames);

I stopped using ini4j for the read part of tableupdate and just used java properties, which helped witht he speed a lot but still did not resolve. setDataVector works just as well as BreakTimev21.jTable1.setValueAt(StartIni2.one(), 0, 1); StartIni2 uses java properties now instead of ini4j.

user1753429
  • 89
  • 1
  • 7

3 Answers3

4

You should not change your table model for every update in your timer. Rather, you should implement your own model, by subclassing AbstractTableModel. Every time the data is updated in your timer, you change only the values of your model that have changed and use the fire*() methods of AbstractTableModel to get Swing to know what you have done.

See the Javadoc and the tutorial.

Cyrille Ka
  • 15,328
  • 5
  • 38
  • 58
  • I understand that, I have read the tutorial and looked at alot of posts. It's just not sinking in. I think I add `BreakTimev21.jTable1.tableChanged(new TableModelEvent(BreakTimev21.jTable1.getModel()));` in the timer instead of remaking the table, but what do I do with this `@Override public void tableChanged(TableModelEvent e) { int row = e.getFirstRow(); int column = e.getColumn(); TableModel model = (TableModel)e.getSource(); String columnName = model.getColumnName(column); Object data = model.getValueAt(row, column); } `? I feel like I am missing something from that. – user1753429 Feb 04 '13 at 22:01
  • I don't know what you are doing here. You said you have read the tutorial but you are still not doing the way it recommends and you present new bunch of code that do not go in that direction (and your tableChanged method does nothing). Maybe you have a perfectly valid reason not to do your stuff in a subclass of AbstractTableModel but we can not help you if we don't know why. – Cyrille Ka Feb 04 '13 at 22:10
  • I mentioned those other options because it's what I found from reading the other posts. It is also in the tutorial. Not sure how to subclass it as an `AbstractTableModel`. the tutorial even says " ...// Do something with the data..." with not explanation of what to do. It also says " consider subclassing AbstractTableModel, If DefaultTableModel is not a suitable. I don't know if DefaultTableModel is suitable or not. None of the oracle exmaples for tables show how to use tablechanged. – user1753429 Feb 04 '13 at 22:40
  • also found a post [http://stackoverflow.com/questions/3540661/tablemodellistener-and-multiple-column-validation] (here) that is kinda of helpful, but the tablechanged means nothing to me. I think I need to put in the ini references I am using, like `AnalaystIni.one()`. – user1753429 Feb 04 '13 at 22:44
2

First of all you should not be extending JLabel to implement the TableUpdate class.

There is no reason you can't use the DefaultTableModel. When you want to change existing data in the model all you do is invoke:

model.setValueAt(...)

and the table will repaint the cell automatically.

So when the Timer fires and its time to update the table you could just create your 2-dimensional array with the new data. Then you loop through the array and compare the value in the array with the value in the model. When you find a difference you update the model as I suggested above.

Or an alternative approach is to keep using your existing model and replace all the data in the model with the data in the array by using the setDataVector() method of DefaultTableModel.

If you use this second approach then after you initial create the JTable you will want to use:

table.setAutoCreateColumnsFromModel(false); 

This will make updating of the model faster since it just updates the data and won't recreate all the TableColumns etc.

Using either of the approaches here there is no need for you to play with the tableChanged() method.

camickr
  • 321,443
  • 19
  • 166
  • 288
  • I was able to get both of them to update, but it is still slow. It's fine for 8 rows, but at 16+ it starts to lag. – user1753429 Feb 05 '13 at 19:07
  • I ended up not using ini4j and just used java props and it helped greatly with the speed, so maybe the problem wasn't with the tables. however you answser helped me the most. thanks! – user1753429 Feb 06 '13 at 16:55
1

The problem is that you're copying your data into an Object[][] array, and using that for the table model. But when your data changes, it's not clear how to tell the table model which value changed.

Instead, subclass AbstractTableModel and override the following (at minimum):

public int getRowCount();
public int getColumnCount();
public Object getValueAt(int row, int column);
isCellEditable(int rowIndex, int columnIndex);
public Object setValueAt(Object aValue, int rowIndex, int columnIndex);

When setValueAt is called, figure out which backing object/property to modify, and modify it. Then call the fireTableCellUpdated(int row, int column) method.

As a side note, the method calls you are using in your AnalystIni seem fishy to me, like they will limit you to eight rows in your table. Consider using a List instead of named values.

Sam Barnum
  • 10,559
  • 3
  • 54
  • 60