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...
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With