Search code examples
javaswingjlabelevent-dispatch-thread

The loading message is not updated when the process starts


I want to display a "loading message" when a process is started and I want to change the message when the process is finished. I tried to update the text from a JLabel before and after the thread with the process is started but the problem is that on the frame appears only the last update.

Here is my code:

import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class MyClass extends JFrame {
    private JLabel loading;
    private JButton jButton;
    private JPanel jPanel;

    public static void main(String[] args) {
        new MyClass();
    }

    MyClass() {
        jPanel = new JPanel();
        setLayout(new GridLayout(0, 1));
        loading = new JLabel("");
        loading.setVisible(true);

        jButton = new JButton("Click me!");
        addActionToJButon();

        setSize(300, 300);
        jPanel.add(jButton);
        jPanel.add(loading);

        add(jPanel);

        setVisible(true);
    }

    private void addActionToJButon() {
        jButton.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                // TODO Auto-generated method stub
            loading.setText("Loading....");
            new Thread(new Runnable() {

                @Override
                public void run() {
                    // TODO Auto-generated method stub
                    for (int i = 0; i <= 1000000; i++) {
                        System.out.println(i);
                    }
                }
            }).start();
            loading.setText("Done!");
            }   
        });
    }
}

I was expecting to appear the label "Loading..." once what the process is started and the message "Done" when the process is finished but I can't find out why on the frame appears the label with the message "Done!".


Solution

  • Thanks to JB Nizet advices I used SwingWorker and the code is working now.

    Here is the correct code:

    package view;
    
    import java.awt.GridLayout;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.util.concurrent.ExecutionException;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JPanel;
    import javax.swing.SwingWorker;
    
    public class MyClass extends JFrame {
        private JLabel loading;
        private JButton jButton;
        private JPanel jPanel;
    
        public static void main(String[] args) {
            new MyClass();
        }
    
        MyClass() {
            jPanel = new JPanel();
            setLayout(new GridLayout(0, 1));
            loading = new JLabel("");
            loading.setVisible(true);
    
            jButton = new JButton("Click me!");
            addActionToJButon();
    
            setSize(300, 300);
            jPanel.add(jButton);
            jPanel.add(loading);
    
            add(jPanel);
    
            setVisible(true);
        }
    
        private void addActionToJButon() {
            jButton.addActionListener(new ActionListener() {
    
                @Override
                public void actionPerformed(ActionEvent e) {
                    // TODO Auto-generated method stub
                    loading.setText("Loading....");
    
                    swingWorker();
                }
            });
        }
    
        private void swingWorker() {
            SwingWorker worker = new SwingWorker<String, String>() {
    
                @Override
                protected String doInBackground() throws Exception {
                    // TODO Auto-generated method stub
                    for (int i = 0; i <= 1000000; i++) {
                        System.out.println(i);
                    }
                    return "Done";
                }
    
                protected void done() {
                    try {
                        String finished =  get();
                        loading.setText(finished);
                    } catch (InterruptedException | ExecutionException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            };
            worker.execute();
        }
    }