0

Can anyone tell me the best way to refresh a JTable ? I have tried to use table.repaint() from another thread, but I don't know if this is the best way.

My code:

Class: Model

public class CLS_ValueUpdater extends Thread {

    private String sRowName;
    private String sValue;

    public CLS_ValueUpdater(String sRowName) {
        this.sRowName = sRowName;
        this.start();
    }

    public String getValue() {
        return this.sValue;
    }

    public String getRowName() {
        return sRowName;
    }

    public void setRowName(String sRowName) {
        this.sRowName = sRowName;
    }

    public void run() {
        try {
            for (int i = 0; i <= 100; i++) {
                this.sValue = String.valueOf(i);

                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Class: Controller

public class CLS_Controller extends AbstractTableModel {

    private static final long serialVersionUID = -5603593230985106202L;
    private String[] sArrColumns = { "Nombre", "Valor" };

    private ArrayList<CLS_ValueUpdater> tListUpdater = new ArrayList<CLS_ValueUpdater>();

    public CLS_Controller() {
        super();
    }

    public void addRow(String sName) {
        this.tListUpdater.add(new CLS_ValueUpdater(sName));
        this.fireTableDataChanged();
    }

    public void deleteRow(int iIndex) {
        this.tListUpdater.remove(iIndex);
        this.fireTableDataChanged();
    }

    @Override
    public String getColumnName(int iColumn) {
        return this.sArrColumns[iColumn];
    }

    @Override
    public int getColumnCount() {
        return this.sArrColumns.length;
    }

    @Override
    public int getRowCount() {
        return this.tListUpdater.size();
    }

    @Override
    public Object getValueAt(int iRow, int iColumn) {
        CLS_ValueUpdater tValueUpdater = this.tListUpdater.get(iRow);

        switch (iColumn) {
        case 0:
            return tValueUpdater.getRowName();
        case 1:
            return tValueUpdater.getValue();
        default:
            return null;
        }
    }

    @Override
    public void setValueAt(Object oValue, int iRow, int iColumn) {
        CLS_ValueUpdater tValueUpdater = this.tListUpdater.get(iRow);

        switch (iColumn) {
        case 0:
            tValueUpdater.setRowName(oValue.toString());
            break;
        }

        this.fireTableCellUpdated(iRow, iColumn);
    }

    @Override
    public Class<String> getColumnClass(int iColumn) {
        return String.class;
    }

    @Override
    public boolean isCellEditable(int rowIndex, int columnIndex) {
        return false;
    }
}

Class: View

public class FRM_Main {

    private JFrame frame;
    private JTable table;
    private CLS_Controller tModel = new CLS_Controller();
    private JTextField textField;
    /**
     * Launch the application.
     */
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            public void run() {
                try {
                    FRM_Main window = new FRM_Main();
                    window.frame.setVisible(true);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });
    }

    /**
     * Create the application.
     */
    public FRM_Main() {
        try {
            for (LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
                if ("Windows".equals(info.getName())) {
                    UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }

        initialize();
    }

    /**
     * Initialize the contents of the frame.
     */
    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 476, 283);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel();
        frame.getContentPane().add(panel, BorderLayout.CENTER);

        JScrollPane scrollPane = new JScrollPane();

        JButton btnNewButton = new JButton("Add");
        btnNewButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                tModel.addRow(textField.getText());
            }
        });

        JButton btnNewButton_1 = new JButton("Delete");

        textField = new JTextField();
        textField.setColumns(10);
        GroupLayout gl_panel = new GroupLayout(panel);
        gl_panel.setHorizontalGroup(gl_panel
                .createParallelGroup(Alignment.LEADING)
                .addGroup(
                        gl_panel.createSequentialGroup()
                                .addContainerGap()
                                .addGroup(
                                        gl_panel.createParallelGroup(
                                                Alignment.LEADING)
                                                .addComponent(
                                                        scrollPane,
                                                        GroupLayout.DEFAULT_SIZE,
                                                        440, Short.MAX_VALUE)
                                                .addGroup(
                                                        Alignment.TRAILING,
                                                        gl_panel.createSequentialGroup()
                                                                .addComponent(
                                                                        textField,
                                                                        GroupLayout.PREFERRED_SIZE,
                                                                        GroupLayout.DEFAULT_SIZE,
                                                                        GroupLayout.PREFERRED_SIZE)
                                                                .addPreferredGap(
                                                                        ComponentPlacement.RELATED)
                                                                .addComponent(
                                                                        btnNewButton)
                                                                .addPreferredGap(
                                                                        ComponentPlacement.RELATED,
                                                                        216,
                                                                        Short.MAX_VALUE)
                                                                .addComponent(
                                                                        btnNewButton_1)))
                                .addContainerGap()));
        gl_panel.setVerticalGroup(gl_panel
                .createParallelGroup(Alignment.LEADING)
                .addGroup(
                        gl_panel.createSequentialGroup()
                                .addContainerGap()
                                .addComponent(scrollPane,
                                        GroupLayout.PREFERRED_SIZE, 194,
                                        GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(ComponentPlacement.RELATED)
                                .addGroup(
                                        gl_panel.createParallelGroup(
                                                Alignment.BASELINE)
                                                .addComponent(btnNewButton_1)
                                                .addComponent(
                                                        textField,
                                                        GroupLayout.PREFERRED_SIZE,
                                                        GroupLayout.DEFAULT_SIZE,
                                                        GroupLayout.PREFERRED_SIZE)
                                                .addComponent(btnNewButton))
                                .addContainerGap(80, Short.MAX_VALUE)));

        table = new JTable();
        table.setShowVerticalLines(false);
        table.setShowHorizontalLines(false);
        table.setFillsViewportHeight(true);
        table.setModel(tModel);

        new tableUpdater(table);

        scrollPane.setViewportView(table);
        panel.setLayout(gl_panel);

    }
}

class tableUpdater extends Thread {

    private JTable tTable;

    public tableUpdater(JTable tTable) {
        this.tTable = tTable;
        this.start();
    }

    public void run() {
        try {
            while (true) {
                tTable.repaint();

                Thread.sleep(2000);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

So is there any elegant way to autoupdate the JTable? Thanks in advance!

mKorbel
  • 109,525
  • 20
  • 134
  • 319
SamYan
  • 1,553
  • 1
  • 19
  • 38

3 Answers3

2

I have tried to use table.repaint() from another thread

If another thread is not the EDT your table is not gonna to be repainted.

You want to update your jtable with a progress bar. You may interested using SwingWorker . Here is a complete example.

class MySwingWorker extends SwingWorker <String,String>{ //what params you want here 

@Override
protected String doInBackground()throws Exception{

   //here you download heavy task
    //and you call publish() when you want 
}

@Override
protected void process(List<String> chunks){
  // here you updated your gui 
   //setValueAt(row,col); and fireTableCellUpdated(row,col);
}

@Override
protected void done(){
  //here is called when doInBackGround is finished
}

}

So then you have to call setValue(int row, int column) and fireTableCellUpdated(int row,int col); with partial results that swingWorker gives you.

BTW When you insert a row

 public void addRow(String sName) {
        this.tListUpdater.add(new CLS_ValueUpdater(sName));
        this.fireTableDataChanged();
 }

May be is better to call

void fireTableRowsInserted(int firstRow, int lastRow)

nachokk
  • 14,363
  • 4
  • 24
  • 53
  • You dont understand me... I need to update the inserted value all the time, because i'm writting a small multidownloader and i need to see the download progress value, so the Jtable will need to update automatically all the time for the download progress. Sorry for my bad english. Thanks for response. – SamYan Jul 16 '13 at 20:06
  • i understand now.. you may interested about `SwingWorker` – nachokk Jul 16 '13 at 20:08
  • @SamuelPedrosa Why don't you use a `JProgressBar` ? – Radu Murzea Jul 16 '13 at 20:13
  • @Radu Murzea - Actually, the question here is to know how to do one thing and not seek alternative. But thanks for the reply. – SamYan Jul 16 '13 at 20:16
  • @SamuelPedrosa i edited answer, hope it helps you – nachokk Jul 16 '13 at 20:29
  • Thank you very much nachokk!!! Is just what I wanted :) – SamYan Jul 16 '13 at 20:41
0

The javadoc of DefaultTableModel#setValueAt () says:

Sets the object value for the cell at column and row. aValue is the new value. This method will generate a tableChanged notification.

So if you change the content by calling model.setValueAt(), that will also trigger a repaint.

Note: model is the TableModel of your JTable.

Radu Murzea
  • 10,724
  • 10
  • 47
  • 69
-1

If you want to refresh your table every 1 seconds, use a separate Thread that does the refresh ; do not forget to use invokeLater method.

new Thread(new Runnable(){
  public void run()
  {
     while(true)
     {
       Thread.sleep(1000);  
       SwingUtilities.invokeLater(new Runnable(){
         public void run() 
         {
           _tableModel.fireTableDataChanged();
         }
       });
     }
  }
}).start();
David
  • 1,138
  • 5
  • 15
  • I had tried that method but if I have selected any row of JTable it is deselected when it refresh, however with Jtable.repaint does not happen. Sorry for bad english. Thanks for response! – SamYan Jul 16 '13 at 20:19
  • 1
    sceleton is proper, all updates must be done on EDT, but don't to call any notifiers out of model, this is important part of model, see answer by @nachokk, – mKorbel Jul 16 '13 at 20:29
  • -1 (emphasizing @mKorbel) don't fire events on behalf of a model - **NEVER-EVER** – kleopatra Jul 17 '13 at 09:54