JFrame does not update until button function terminates

0

When I click the button it calls a method, and until that method finishes the JFrame does not update

the program is in the image below

privatevoidjButtonBuscarActionPerformed(java.awt.event.ActionEventevt){jTextArea.setText("");
     AtualizeStats("Buscando Dispositivos");
     if (bioSignals.SearchDevice())
     {
         jButtonIniciar.setEnabled(true);
     }
 } 

The method that actually takes is what is within the if condition, but what comes before should basically appear instantly, because the UpdateStats method only changes the text of the black and printable box on the console:

public void AtualizeStats(String stats)
{
    System.out.println(stats);
    jTextArea.append(stats + "\n");
}

What happens is that on the console it appears "Searching Devices" instantly but JFrame waits until everything is in the button listener to be executed

    
asked by anonymous 19.10.2017 / 21:32

1 answer

2

In order to run tasks without crashing the GUI, you need to use the class SwingWorker because it was meant to parallel time-consuming tasks of EDT , which is the thread that manages the graphical user interface in swing.

Within this class, you will delegate the task to the doInBackground() method, which runs in a separate pool, so that the screen continues to function as the task executes. You can also display progress with the publish() and process() classes, and display some termination warning through the done() class.

I will not go into the details of each method because it is not the purpose of the answer, but I will leave some links to study in the end. Here is an example of using SwingWorker , similar to what you are doing, there are comments in relevant snippets:

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
import javax.swing.border.EmptyBorder;
import java.util.List;

public class SwingWorkeSimpleExample extends JFrame {

    private static final long serialVersionUID = 1L;
    private JPanel contentPane;
    private JPanel northPanel;
    private JButton btnSearch;
    private JScrollPane scrollPane;
    private JTextArea textArea;
    private JProgressBar progressBar;

    public static void main(String[] args) {
        EventQueue.invokeLater(SwingWorkeSimpleExample::new);
    }

    public SwingWorkeSimpleExample() {
        setTitle("SwingWorker Test");
        initComponents();
        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void initComponents() {

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setPreferredSize(new Dimension(350, 300));
        this.contentPane = new JPanel();
        this.contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        this.contentPane.setLayout(new BorderLayout(0, 0));
        setContentPane(this.contentPane);

        this.northPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT, 5, 5));
        this.contentPane.add(this.northPanel, BorderLayout.NORTH);

        this.btnSearch = new JButton("Search...");
        this.btnSearch.addActionListener(new ActionWorker());
        this.northPanel.add(this.btnSearch);

        this.textArea = new JTextArea();
        this.textArea.setBackground(Color.BLACK);
        this.textArea.setForeground(Color.WHITE);

        this.scrollPane = new JScrollPane(this.textArea);
        this.scrollPane.setBorder(new EmptyBorder(2, 0, 2, 0));
        this.contentPane.add(this.scrollPane, BorderLayout.CENTER);

        this.progressBar = new JProgressBar(0, 10);
        this.contentPane.add(this.progressBar, BorderLayout.SOUTH);
    }

    private void textAreaAppend(String str) {
        this.textArea.append(str + System.lineSeparator());
    }

    class ActionWorker implements ActionListener {

        @Override
        public void actionPerformed(ActionEvent e) {

            SwingWorker<Void, Integer> worker = new SwingWorker<Void, Integer>() {

                @Override
                protected Void doInBackground() throws Exception {
                    //aqui tudo ocorrerá em paralelo a gui
                    //desativo o botão, adiciono uma mensagem inicial
                    btnSearch.setEnabled(false);
                    textAreaAppend("Searching...");
                    //laço que alimenta a barra de progresso apenas para exemplo
                    for (int i = 0; i < progressBar.getMaximum(); i++) {

                        if (i > 0 && i % 4 == 0)
                            textAreaAppend("Wait...");
                        Thread.sleep(500);
                        //esse metodo "publica" atualizações da tarefa
                        //para a que a barra de progresso seja alimentada
                        //conforme o incremento do laço
                        publish(i);
                    }

                    textAreaAppend("Done!");
                    return null;
                }

                @Override
                protected void process(List<Integer> chunks) {
                    //este métodor recebe o que foi "publicado"
                    // no doInBackground para que possamos atualizar
                    //o progresso na tela
                    progressBar.setValue(chunks.stream().reduce(Integer::sum).orElse(0));
                }

                @Override
                protected void done() {
                    //entrará aqui quando terminar a tarefa, ou
                    //ocorrer alguma exceção
                    progressBar.setValue(0);
                    btnSearch.setEnabled(true);
                }
            };
            worker.execute();
        }
    }
}

Running:

  • Worker Threads and SwingWorker

  • link

21.10.2017 / 02:17