Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple JFrame issue

The issue here is that after asking a user for the settings of a neural network through a settings JFrame, the new JFrame meant to visualise the network learning only seems to display something after the network is done looping through all the data.

I believe this is because I use a SwingWorker and the loop doesn't wait for it to finish doing the calculations and displaying the result before going onto the next cycle.

Step 1: I ask the user for parameters with a JFrame

public class Settings {

private int width = 1920 / 4;
private int height = 1080 / 4;

private JFrame settings;
private JButton startButton;

public static void main(String[] args) {
    Settings settings = new Settings();
    settings.start();
}

private void start() {
    settings = new JFrame();
    settings.setTitle("Settings");
    settings.setSize(width, height);
    settings.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    startButton = new JButton("start");
    startButton.addActionListener(new FieldListener());
    settings.getContentPane().add(startButton);

    settings.pack();
    settings.setVisible(true);
}

class FieldListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
        if (e.getSource() == startButton) {
            prepare();
        }
    }
}

public void prepare() {
    Control control = new Control();
    control.start(amountOfNeurons);
}

Step 2: A control class creates the neural network with the specified parameters, and then feeds it the data

public class Control {

public void start(int amountOfNeurons) {
    Network net = new Network(amountOfNeurons);
    int[][] data = getData();
    net.startLearning(data);
}

Step 3: The network iterates through the data given to learn

public class Network {

int amountOfNeurons;
Visualiser vis;

public Network(int amountOfNeurons) {
    this.amountOfNeurons = amountOfNeurons;
}

public void startLearning(int[][] data) {
    vis = new Visualiser();
    JFrame graph = new JFrame();
    graph.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    graph.setSize(1920, 1080);
    graph.setTitle("Graph");
    graph.getContentPane().add(vis);
    graph.setResizable(false);
    graph.pack();
    graph.setVisible(true);

    for(int i = 0; i < data.length; i++) {
        new TrainTask(data[i]);
    }
}

class TrainTask extends SwingWorker<Void,Void> {
    int[] data;


    public TrainTask(int[] data) {
        this.data = data;
    }

    @Override
    public Void doInBackground() {
        for(int i = 0; i < data.length; i++) {
            calculate(data);
            vis.result = calculate(data);
            vis.repaint();
            System.out.println(i);
        }
        return null;
    }
}

As @c0der and @Frakcool suggested I use a SwingWorker to do the heavy load, i.e. loop through the data and update the visualiser

But the program continues without waiting on the response of the SwingWorker... I would like to try invokeAndWait() so that the program waits, but the network itself is run on the EDT, so it causes the program to crash.

What should I do differently?

P.S. I would like to point out that when I don't create the settings class, and create the network from a main method in the control class, everything seems to work fine...

like image 259
Tugdual Kerjan Avatar asked Aug 22 '26 20:08

Tugdual Kerjan


1 Answers

The code posted is not mcve because prepare is never invoked. Network executes a long process which blocks the EDT. Once this process is invoked, statements following it are not executed until the long process ends.
This can be demonstrated easily
by this mcve:

import java.awt.Point;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;

public class Network {

    Network() throws InterruptedException {

        Visualiser visualiser = new Visualiser();
        JFrame graph = new JFrame();
        graph.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        graph.setLocation(new Point(150,150));
        graph.getContentPane().add(visualiser);
        graph.pack();
        graph.setVisible(true);

        for(int i = 0; i < 100; i++) {
            visualiser.setText(String.valueOf(i));
            Thread.sleep(500);
            visualiser.repaint();
        }
    }

    public static void main(String[] args) throws InterruptedException {
        JFrame settings = new JFrame();
        settings.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        settings.add(new JLabel("settings"));
        new Network(); //invoke Network before settings is made visible 
        settings.pack();
        settings.setVisible(true);
    }
}

class Visualiser extends JPanel {

    JLabel lable;
    Visualiser(){
        lable = new JLabel("0");
        add(lable);
    }

    void setText(String s) {
        lable.setText(s);
    }
}

settings becomes visible only after counting ends.
Changing the execution order to

settings.setVisible(true);
new Network();

causes settings to show before counting is executed.
However this is not the right cure for this problem. It is posted to explain the problem.
Long processes should not be invoked on EDT. The right solution, as suggested by Fracool is to use a SwingWorker to take the long process OFF the EDT:

public class Network {

    Visualiser visualiser;
    Network() throws InterruptedException {

        visualiser = new Visualiser();
        JFrame graph = new JFrame();
        graph.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        graph.setLocation(new Point(150,150));
        graph.getContentPane().add(visualiser);
        graph.pack();
        graph.setVisible(true);
        new VisulizerUpdateTask().execute();
    }

    //use swing worker perform long task
    class VisulizerUpdateTask extends SwingWorker<Void,Void> {

        @Override
        public Void doInBackground() {
            for(int i = 0; i < 100; i++) {
                visualiser.setText(String.valueOf(i));
                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) { ex.printStackTrace();   }
                visualiser.repaint();
            }
            return null;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        JFrame settings = new JFrame();
        settings.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        settings.add(new JLabel("settings"));
        new Network();
        settings.pack();
        settings.setVisible(true);
    }
}

Also note the link posted by Andrew Thompson.

like image 166
c0der Avatar answered Aug 25 '26 10:08

c0der



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!