Search code examples
javamultithreadingswingjframeswingworker

Repeat SwingWorker


I want to build a JFrame able to run a background task every time a JButton was clicked.currently i am using a swing worker and it wont allow the task to be executed more than once.

How can I enable repetition task for SwingWorker with JButton click.

public class ScanFileFrame extends JFrame{

    JButton btnTicking;
    JLabel label1;

    ScanFileFrame(){

        JFrame jframe = new JFrame();
        jframe.setLayout(new FlowLayout());
        btnTicking = new JButton("Start Scanning Files");
        label1 = new JLabel("No File Scanned");

        btnTicking.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent arg0) {
                worker.execute();

            }   
        });

        jframe.add(btnTicking);
        jframe.add(label1);

        jframe.setVisible(true);
        jframe.setSize(300,300);
    }

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

        @Override
        protected Boolean doInBackground() throws Exception {

           // Simulate scan file
           System.out.println("scanning files ....");
           Thread.sleep(2000);

           return true;

        }

        //update jframe jlabel when background task finish
        protected void done() {
            label1.setText("Files Scanned");
            System.out.println("complete");
        }
    };

    public static void main(String[] args){
        ScanFileFrame f = new ScanFileFrame();

    }
}

Solution

  • currently i am using a swing worker and it wont allow the task to be executed more than once.

    This is not an issue since you would just construct a new SwingWorker and run it within your JButton's ActionListener. As far as I can tell, this is the solution to your question as it is currently written. If you need a more detailed answer, then you'll want to provide more detail in your question.


    Edit You state:

    but i have no idea how to reinvent the swingworker everytime the user click the scan button.

    How do you "reinvent" any object? By creating a new instance, here a new MySwingWorker, and then call execute on it.


    e.g.,

    import java.awt.*;
    import java.awt.event.*;
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.util.concurrent.ExecutionException;
    
    import javax.swing.*;
    
    public class ScanFileFrame {
       private FileScanAction fileScanAction = new FileScanAction("Scan Files", KeyEvent.VK_S);
       private JButton btnTicking = new JButton(fileScanAction);
       private JLabel label1;
       private MyFileScanWorker worker;
    
       ScanFileFrame() {
    
          JFrame jframe = new JFrame();
          jframe.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
          jframe.setLayout(new FlowLayout());
          label1 = new JLabel("       No File Scanned       ", SwingConstants.CENTER);
    
          jframe.add(btnTicking);
          jframe.add(label1);
          jframe.pack();
          jframe.setLocationByPlatform(true);
          jframe.setVisible(true);
    
       }
    
       @SuppressWarnings("serial")
       private class FileScanAction extends AbstractAction {
          public FileScanAction(String name, int mnemonic) {
             super(name);
             putValue(MNEMONIC_KEY, mnemonic);
          }
    
          @Override
          public void actionPerformed(ActionEvent e) {
             label1.setText("Scanning Files");
             fileScanAction.setEnabled(false);
             worker = new MyFileScanWorker();
             worker.addPropertyChangeListener(new WorkerListener());
             worker.execute();
          }
       }
    
       private class WorkerListener implements PropertyChangeListener {
          @Override
          public void propertyChange(PropertyChangeEvent pcEvt) {
             if (pcEvt.getNewValue() == SwingWorker.StateValue.DONE) {
                fileScanAction.setEnabled(true);
                try {
                   boolean success = worker.get();
                   String text = success ? "Scanning Successful" : "Scanning Error";
                   label1.setText(text);
                } catch (InterruptedException | ExecutionException e) {
                   e.printStackTrace();
                }
             }
          }
       }
    
       private class MyFileScanWorker extends SwingWorker<Boolean, Void> {
    
          @Override
          protected Boolean doInBackground() throws Exception {
             // Simulate scan file
             Thread.sleep(2000);
    
             // have it work successfully 2/3 of the time.
             if (Math.random() > 0.3333) {
                return true;
             } else {
                return false;
             }
          }
       };
    
       public static void main(String[] args) {
          SwingUtilities.invokeLater(new Runnable() {
             public void run() {
                new ScanFileFrame();
             }
          });
       }
    }
    

    Note that you always want to call get() on your SwingWorker after it has completed, even if it returns null, so that you can trap any exceptions that might have occurred during the SwingWorker's run.