Search code examples
javaswingswingworker

Any way for a class that has already extended any other class to extend or implement a SwingWorker


I want to extend SwingWorker for a class but I have already extended one other class for that. I wanted to know whether there is some sort of a workaround like in threads (we can extend it or implement it), so that I maybe able to use in doInBackground method of SwingWorker.

I have a list of objects on which I need to perform an operation .The objects are of type A,B,C. I have made a superclass S and A,B,C are the sub classes for that superclass. I have an object of S and at runtime while going through the list I find the type of the item in the list and typecast the S to A,B or C and perform the operation . If I make S a SwingWorker, I can perform the operation only once, since Swing workers can be used only once. I can't make A,B,C extend SwingWorker because they are already extending S. So I need to implement SwingWorker for A,B,C

I also have a Connection object that A,B,C would use and I have made it as a Singleton because I don't want to initialize again and again.


Solution

  • An example composition example follows.

    Expected output:

    Received partial update list [Worker: start]

    Progress: 20%...

    Progress: 70%...

    Progress: 100%...

    Received partial update list [Worker: woken up, Worker: sending the result]

    Worker Done

    Launcher done.

    Code:

    package com.stackoverflow;
    
    import java.beans.PropertyChangeEvent;
    import java.beans.PropertyChangeListener;
    import java.util.List;
    
    import javax.swing.SwingWorker;
    
    public class DelegatingSwingWorkerDemo {
    
        public static void main(String[] args) {
            new Launcher().launch();
        }
    }
    
    /**
     * Use this, to launch the worker.
     */
    class DelegatingSwingWorker<I, O> extends SwingWorker<I, O> {
    
        SwingWorkerable<I, O> delegate;
    
        Publisher<O> publisher;
    
        public DelegatingSwingWorker(SwingWorkerable<I, O> delegate) {
            this.delegate = delegate;
    
            publisher = new Publisher<O>() {
    
                @Override
                public void publish(O... chunks) {
                    DelegatingSwingWorker.this.publish(chunks);
                }
    
                @Override
                public void setProgress(int progress) {
                    DelegatingSwingWorker.this.setProgress(progress);
                }
            };
        }
    
        @Override
        protected void process(List<O> chunks) {
            delegate.process(chunks);
        }
    
        @Override
        protected void done() {
            delegate.done();
        }
    
        @Override
        protected I doInBackground() throws Exception {
            return delegate.doInBackground(publisher);
        }
    
    }
    
    interface Publisher<O> {
    
        void publish(O... chunks);
    
        void setProgress(int progress);
    }
    
    /**
     * Make your class implement the interface.
     */
    interface SwingWorkerable<I, O> {
    
        void process(List<O> chunks);
    
        I doInBackground(Publisher<O> publisher);
    
        void done();
    
    }
    
    /**
     * Let's say this is your super class:
     */
    
    class MySuperClass {
    
    }
    
    /**
     * Use your super class, but implement the SwingWorkerable. Then
     * launch using a DelegatingSwingWorker
     */
    class SleepingDemoSwingWorkerable
        extends MySuperClass
        implements SwingWorkerable<String, String> {
    
        @Override
        public void process(List<String> chunks) {
            System.out.println("Received partial update list " + chunks);
        }
    
        @Override
        public String doInBackground(Publisher<String> publisher) {
            publisher.publish("Worker: start");
            try {
                publisher.setProgress(0);
                Thread.sleep(200);
                publisher.setProgress(20);
                Thread.sleep(500);
                publisher.setProgress(70);
                Thread.sleep(300);
                publisher.setProgress(100);
                publisher.publish("Worker: woken up");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            publisher.publish("Worker: sending the result");
            return "Second passed.";
        }
    
        @Override
        public void done() {
            System.out.println("Worker Done");
        }
    
    }
    
    final class ConsoleProgressListener implements PropertyChangeListener {
    
        @Override
        public void propertyChange(PropertyChangeEvent event) {
            switch (event.getPropertyName()) {
            case "progress":
                System.out.println("Progress: " + event.getNewValue() + "%...");
            }
        }
    }
    
    /**
     * Launch
     */
    class Launcher {
    
        public void launch() {
            SleepingDemoSwingWorkerable workerable = new SleepingDemoSwingWorkerable();
            DelegatingSwingWorker<String, String> delegatingSwingWorker =
                    new DelegatingSwingWorker<String, String>(workerable);
            delegatingSwingWorker.addPropertyChangeListener(new ConsoleProgressListener());
            delegatingSwingWorker.execute();
    
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            System.out.println("Launcher done.");
        }
    }