Question

The following code is a simple JFrame with a button and two JLabels, the objective of the code is to update the ""number JLabel by invoking a new Thread, instead of trying to do it in the EDT.

My problem is that the run method invokes a new thread each time you press the button, however, it does not cancel the old one. Therefore, if you press the button, and press it again a couple of seconds later you will have two threads updating the JLabel, and this looks crappy.

PROBLEM STATEMENT: Every time You press the button, the counter has to start at 0, and the old thread that was updating it, has to be cancelled.

import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import java.util.concurrent.ExecutionException;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;

public class MainFrame extends JFrame {

private JLabel countLabel1 = new JLabel("0");
private JLabel statusLabel = new JLabel("Task not completed.");
private JButton startButton = new JButton("Start");

public MainFrame(String title) {
    super(title);

    setLayout(new GridBagLayout());

    countLabel1.setFont(new Font("serif", Font.BOLD, 28));

    GridBagConstraints gc = new GridBagConstraints();

    gc.fill = GridBagConstraints.NONE;

    gc.gridx = 0;
    gc.gridy = 0;
    gc.weightx = 1;
    gc.weighty = 1;
    add(countLabel1, gc);

    gc.gridx = 0;
    gc.gridy = 1;
    gc.weightx = 1;
    gc.weighty = 1;
    add(statusLabel, gc);

    gc.gridx = 0;
    gc.gridy = 2;
    gc.weightx = 1;
    gc.weighty = 1;
    add(startButton, gc);

    startButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent arg0) {
            start();
        }
    });

    setSize(200, 400);
    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setVisible(true);
}


private void start() 
{
    Thread worker = new Thread() 
    {
        public void run() 
        {

            // Simulate doing something useful.
            for(int i=0; i<=10; i++) {

                final int count = i;

                SwingUtilities.invokeLater(new Runnable() 
                {
                    public void run() 
                    {
                        countLabel1.setText(Integer.toString(count));
                    }
                });

                try 
                {
                    Thread.sleep(1000);
                } catch (InterruptedException e) 
                {

                }
            }

            SwingUtilities.invokeLater(new Runnable() {
                public void run() 
                {
                    statusLabel.setText("Completed.");
                }
            });

        }
    };

    worker.start();
}

public static void main(String[] args) {
    SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            new MainFrame("SwingWorker Demo");
        }
    });
 }
   }
Was it helpful?

Solution

Use some flag to stop previous thread as simple as it is.

One more thing that you are not updating statusLabel when button is clicked next time.

Try this one

import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
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.SwingUtilities;

public class MainFrame extends JFrame {

    private JLabel countLabel1 = new JLabel("0");
    private JLabel statusLabel = new JLabel("Task not completed.");
    private JButton startButton = new JButton("Start");

    private MyThread myThread;

    public MainFrame(String title) {
        super(title);

        setLayout(new GridBagLayout());

        countLabel1.setFont(new Font("serif", Font.BOLD, 28));

        GridBagConstraints gc = new GridBagConstraints();

        gc.fill = GridBagConstraints.NONE;

        gc.gridx = 0;
        gc.gridy = 0;
        gc.weightx = 1;
        gc.weighty = 1;
        add(countLabel1, gc);

        gc.gridx = 0;
        gc.gridy = 1;
        gc.weightx = 1;
        gc.weighty = 1;
        add(statusLabel, gc);

        gc.gridx = 0;
        gc.gridy = 2;
        gc.weightx = 1;
        gc.weighty = 1;
        add(startButton, gc);

        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                start();
            }
        });

        setSize(200, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    private void start() {
        if (myThread != null) {
            myThread.setRunning(false);
        }
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                statusLabel.setText("Task not completed.");
            }
        });
        myThread = new MyThread(countLabel1, statusLabel);
        Thread thread = new Thread(myThread);
        thread.start();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new MainFrame("SwingWorker Demo");
            }
        });
    }
}

class MyThread implements Runnable {

    public MyThread(JLabel countLabel1, JLabel statusLabel) {
        this.countLabel1 = countLabel1;
        this.statusLabel = statusLabel;
    }

    private boolean running = true;
    private JLabel countLabel1, statusLabel;

    public void run() {

        // Simulate doing something useful.
        for (int i = 0; i <= 10; i++) {

            if (running) {
                final int count = i;

                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        if (running) {
                            countLabel1.setText(Integer.toString(count));

                            if (count == 10) {
                                SwingUtilities.invokeLater(new Runnable() {
                                    public void run() {
                                        statusLabel.setText("Completed.");
                                    }
                                });
                            }
                        }
                    }
                });
            } else {
                break;
            }

            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {

            }
        }

    }

    public boolean isRunning() {
        return running;
    }

    public void setRunning(boolean running) {
        this.running = running;
    }

}

OTHER TIPS

Check this version of your code. The main new thing is the Updater class which implements Runnable. See how it is used here. See also the changes in private void start(). See also the enabled flag in the Updater class.

import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
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.SwingUtilities;

public class MainFrame extends JFrame {

    public static final long serialVersionUID = 380931874973423432L;
    private Updater currentUpdater = null;
    private Thread currentWorker = null;
    private int cnt = 0;

    private JLabel countLabel1 = new JLabel("0");
    private JLabel statusLabel = new JLabel("Initialized.");
    private JButton startButton = new JButton("Start");

    public MainFrame(String title) {
        super(title);

        setLayout(new GridBagLayout());

        countLabel1.setFont(new Font("serif", Font.BOLD, 28));

        GridBagConstraints gc = new GridBagConstraints();

        gc.fill = GridBagConstraints.NONE;

        gc.gridx = 0;
        gc.gridy = 0;
        gc.weightx = 1;
        gc.weighty = 1;
        add(countLabel1, gc);

        gc.gridx = 0;
        gc.gridy = 1;
        gc.weightx = 1;
        gc.weighty = 1;
        add(statusLabel, gc);

        gc.gridx = 0;
        gc.gridy = 2;
        gc.weightx = 1;
        gc.weighty = 1;
        add(startButton, gc);

        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent arg0) {
                start();
            }
        });

        setSize(400, 400);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        setVisible(true);
    }

    private void start() {

        cnt++;

        Thread cw = this.currentWorker;
        if (currentUpdater != null) {
            currentUpdater.setEnabled(false);
        }

        Updater newUpdater = new Updater(this, cnt);
        Thread newWorker = new Thread(newUpdater);

        try{
            if (cw!=null) 
                cw.join();
        }catch(InterruptedException ex){
            ex.printStackTrace();
        }

        this.currentUpdater = newUpdater;
        this.currentWorker = newWorker;

        newWorker.start();
    }

    public JLabel getCountLabel1() {
        return countLabel1;
    }

    public void setCountLabel1(JLabel countLabel1) {
        this.countLabel1 = countLabel1;
    }

    public JLabel getStatusLabel() {
        return statusLabel;
    }

    public void setStatusLabel(JLabel statusLabel) {
        this.statusLabel = statusLabel;
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new MainFrame("SwingWorker Demo");
            }
        });
    }
}

class Updater implements Runnable {

    private int id = 0;
    private MainFrame frame = null;
    private volatile boolean enabled = false;

    public Updater(MainFrame f, int id) {
        this.frame = f;
        this.id = id;
    }

    public void run() {
        enabled = true;

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                frame.getStatusLabel().setText("Task not completed. Task ID: " + id);
                System.out.println("Task not completed. Task ID: " + id);
            }
        });

        // Simulate doing something useful.
        for (int i = 0; i <= 10; i++) {

            if (!enabled)
                break;

            final int count = i;

            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    frame.getCountLabel1().setText(Integer.toString(count));
                }
            });

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

        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                frame.getStatusLabel().setText("Task completed. Task ID: " + id);
                System.out.println("Task completed. Task ID: " + id);
            }
        });

    }

    public boolean isEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top