Lucky
Lucky

Reputation: 11

How to use Swingworker do to run cod in a background thread

I have a program that runs a given test and shows the results using GUI. I need from the program to not freeze when I run a long test. I do all the tests in tester class that starts when we press the run button.

import java.lang.reflect.*; 

public class Tester {
private int setUp;
private int tearDown;
private int fail;
private int success;
private int exceptionFail;
private boolean hasSetup;
private boolean hasTeardown;
private boolean ready;
private String Name;
private Method\[\] methods;
private Class\<?\> test;
private String txtOutput;

    public Tester() {
        hasSetup = false;
        hasTeardown = false;
        ready = false;
        this.txtOutput = "";
    }
    
    
    public Boolean checkTest(String Name) {
        this.Name = Name;
        ready = false;
        if (isValidClass() && isATestClass(this.test)) {
            methods = this.test.getMethods();
            checkSetUpTearDown();
            ready = true;
            return true;
        }
        return false;
    }
    
    
    
    private void checkSetUpTearDown() {
        for (int i = 0; i < methods.length;i++) {
            if ((methods[i].getName().compareTo("setUp") == 0) &&
                    (methods[i].getParameterCount() == 0)) {
                hasSetup = true;
                setUp = i;
            } else if ((methods[i].getName().compareTo("tearDown")) == 0 &&
                    (methods[i].getParameterCount() == 0)) {
                hasTeardown = true;
                tearDown = i;
    
            }
        }
    }
    
    
    private boolean isValidClass() {
        try {
            boolean valid = false;
            test = Class.forName(Name);
            if (test.isInterface()) {
                txtOutput = txtOutput.concat("Class is Interface and cannot be a test\n");
                return false;
            }
            Constructor<?>[] constructors = test.getConstructors();
            for (Constructor con : constructors) {
                if (con.getParameterCount() == 0) {
    
                    break;
                }
            }
            if (false) {
                txtOutput = txtOutput.concat("Could not find a constructor that does not take any          arguments\n");
            }
            return true;
        } catch (ClassNotFoundException e) {
            txtOutput = txtOutput.concat("Could not find class: " + Name + "\n");
        } catch (NoClassDefFoundError e) {
            txtOutput = txtOutput.concat("Could not find class: " + Name + " (Check spelling)\n\n");
        }
        return false;
    }
    

    private boolean isATestClass(Class<?> c) {
        Class<?>[] interfaces = c.getInterfaces();
        for (Class<?> anInterface : interfaces) {
            if (anInterface.getName().compareTo("se.umu.cs.unittest.TestClass") == 0) {
                return true;
            }
        }
        txtOutput = txtOutput.concat("Class does not implement the interface " +
                "se.umu.cs.unittest.TestClass.\n");
        return false;
    }
    
    
    public void runTests() {
        if (ready) {
            try {
                Object klass = test.getDeclaredConstructor().newInstance();
                for (int i = 0; i < methods.length; i++) {
                    String methodName = methods[i].getName();
    
                    if (!methodName.startsWith("test") ||
                            (methods[i].getReturnType() != boolean.class) ||
                            (methods[i].getParameterCount() > 0)) {
                        continue;
                    }
                    runMethod(klass, methodName, i);
                }
            } catch (InstantiationException e) {
                txtOutput = txtOutput.concat("The class could not be " +
                        "initialized. This could be caused " +
                        "by the class being abstract" +
                        " or an array class or a primitive type.\n");
            } catch (IllegalAccessException e) {
                txtOutput = txtOutput.concat("Could not access the class or " +
                        "it's constructor.\n");
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            txtOutput = txtOutput.concat("\n" + success + "tests succeeded\n" );
            txtOutput = txtOutput.concat(fail + "tests failed\n" );
            txtOutput = txtOutput.concat(exceptionFail + "tests failed because of an exception\n\n" );
    
            success = 0;
            fail = 0;
            exceptionFail = 0;
        }
    }
    
    
    private void runMethod(Object klass, String methodName, int methodIndex) {
        try{
            boolean methodReturn;
            if (hasSetup) {
                methods[setUp].invoke(klass);
            }
            methodReturn = (Boolean) methods[methodIndex].invoke(klass);
            if (methodReturn) {
                txtOutput = txtOutput.concat(methodName+": SUCCESS\n");
                success++;
            } else {
                txtOutput = txtOutput.concat(methodName+": FAIL\n");
                fail++;
            }
    
            if (hasTeardown) {
                methods[tearDown].invoke(klass);
            }
        } catch (InvocationTargetException e) {
            txtOutput = txtOutput.concat(methodName + ": FAIL Generated a " + e.getTargetException() + "\n");
            exceptionFail++;
        } catch (IllegalAccessException e) {
            txtOutput = txtOutput.concat("Could not access the the method " + methodName + "\n");
        }
    }
    
    
    public String getTxtOutput() {
        String temp = txtOutput;
        txtOutput = "";
        return temp;
    }

}

Run button class:

import javax.swing.*;
import java.awt.event.*;


public class RunButton implements ActionListener {

    private Tester tester;
    private UserInterface gui;


    public RunButton(UserInterface gui) {
        tester = new Tester();
        this.gui = gui;
    }



    public void actionPerformed(ActionEvent e){
        if(tester.checkTest(gui.getText())){
                tester.runTests();

        }
        gui.setTxtOutputCont(tester.getTxtOutput());

    }




}

I know that I have to use Swingworker to run the tester class in background on another thread, but could not figure out how to do that.

Upvotes: 0

Views: 61

Answers (1)

Gilbert Le Blanc
Gilbert Le Blanc

Reputation: 51445

Oracle has a helpful tutorial, Creating a GUI With Swing. Skip the Learning Swing with the NetBeans IDE section. Pay particular attention to the Concurrency in Swing section.

Coding a SwingWorker is fairly straightforward. You put the background code in the doInBackground method and any code to be executed when the background processing is done in the done method.

The only "trick" is specifying the return types of the doInBackground method and the done method.

Here's your modified RunButton class. I didn't test the code, so if it doesn't work, edit your question to provide a minimum, reproducible example that we can compile in our IDE and test.

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

import javax.swing.SwingWorker;

public class RunButton implements ActionListener {

    private Tester tester;
    private UserInterface gui;

    public RunButton(UserInterface gui) {
        this.tester = new Tester();
        this.gui = gui;
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        SwingWorker<Void, Void> worker = new SwingWorker<Void, Void>() {
            @Override
            public void doInBackground() {
                if (tester.checkTest(gui.getText())) {
                    tester.runTests();
                }
            }

            @Override
            public void done() {
                gui.setTxtOutputCont(tester.getTxtOutput());
            }
        };
    }

}

Upvotes: 0

Related Questions