Update JTable after each change of data in a cell

1

I'm using java

asked by anonymous 20.03.2016 / 18:58

1 answer

2

This happens because you are looping and incrementing progress within the Event Dispatch Thread (EDT) , and this Thread will execute all the code that is in it before updating the container (JFrame, Jpanel, etc) and its components.

To update the table and progress on each line, you need to update the TableModel to a Thread parallel, and the best way to do this together with the EDT is to use SwingWorker .

I made a simple example just to demonstrate the operation of SwingWorker with EDT, the main passages about progress work are commented on:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.table.*;
import java.util.List;

public class ProgressWithSwingWorker extends JFrame {

    private JButton btnChecar;
    private JProgressBar progressBar;
    private JScrollPane ScrollPane;
    private JTable tabela;

    public ProgressWithSwingWorker() {
        initComponents();
    }

    private void initComponents() {

        ScrollPane = new JScrollPane();
        btnChecar = new JButton();
        progressBar = new JProgressBar();

        String[] columns = {"coluna 1", "coluna 2", "coluna 3", "coluna 4"};
        Object[][] data = new Object[][]{
            {null, null, null, null},
            {null, null, null, null},
            {null, null, null, null},
            {null, null, null, null},
            {null, null, null, null},
            {null, null, null, null}
        };

        DefaultTableModel model = new DefaultTableModel(data, columns) {
            @Override
            public Class<?> getColumnClass(int columnIndex) {
                if (columnIndex == 3) {
                    return Boolean.class;
                } else {
                    return super.getColumnClass(columnIndex);
                }
            }
        };

        tabela = new JTable(model);

        ScrollPane.setViewportView(tabela);
        btnChecar.setText("Checar");
        //A "mágica" acontece na classe ChecarComSwingWorker
        btnChecar.addActionListener(new ChecarComSwingWorker());

        this.setLayout(new BorderLayout());
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.add(ScrollPane, BorderLayout.NORTH);
        this.add(btnChecar, BorderLayout.CENTER);
        this.add(progressBar, BorderLayout.SOUTH);

        pack();
    }

    public static void main(String args[]) {

        EventQueue.invokeLater(() -> new ProgressWithSwingWorker().setVisible(true));
    }

    class ChecarComSwingWorker implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {

            final int totalRows = tabela.getModel().getRowCount();
            progressBar.setMaximum(totalRows);
            progressBar.setMinimum(0);
            //passei parametros para facilitar o entendimento
            //- o primeiro é o retorno do doInBackground(não foi necessario uso neste exemplo)
            //- o segundo é o tipo do valor usado entre o publish e o process
            SwingWorker<Object, Integer> worker = new SwingWorker<Object, Integer>() {

                //este método é que executa em uma Thread paralela
                //todo processamento pesado que deve ser executado
                //fora da EDT, deve ser executado aqui 
                @Override
                protected Object doInBackground() {
                    for (int i = 0; i < totalRows; i++) {
                        try {
                            Boolean status = (Boolean) tabela.getModel().getValueAt(i, 3);
                            status = status == null ? true : !status;
                            tabela.getModel().setValueAt(status, i, 3);
                            //este método é que atualiza a barra de progresso
                            //passando cada iteração para o método process
                            publish(i);
                            Thread.sleep(400);
                        } catch (Exception ex) {
                            ex.printStackTrace();
                        }
                    }
                    return null;
                }

                //este método é que recebe o que é passado no publish
                //e atualiza a barra de progresso na EDT
                @Override
                protected void process(List<Integer> chunks) {
                    int valueRecent = chunks.get(chunks.size() - 1);
                    progressBar.setValue(valueRecent + 1);
                }

                //só é executado quando o doInBackground termina
                //o processamento
                @Override
                protected void done() {
                    progressBar.setValue(0);
                }
            };

            worker.execute();
        }
    }
}

And the result is:

HerearesomelinkstousingSwingWorker:

11.5 - Difficulties with Threads and competition - Caelum

Working with SwingWorker in Java - DevMedia

Capturing exceptions in the execution of swingworker

Pass the execution from one method to another as argument

    
21.03.2016 / 01:15