多个 JFrame 问题

Multiple JFrame issue

这里的问题是,在通过设置 JFrame 询问用户神经网络的设置后, 旨在可视化网络学习的新 JFrame 似乎只显示一些东西 在网络完成所有数据的循环后

我相信这是因为我使用了 SwingWorker 并且循环不等待它完成计算并在进入下一个循环之前显示结果。

第 1 步:我使用 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);
}

第 2 步:控件 class 创建具有指定参数的神经网络,然后将数据提供给它

public class Control {

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

第三步:网络遍历给定的数据进行学习

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;
    }
}

正如@c0der 和@Frakcool 所建议的那样,我使用 SwingWorker 来完成繁重的负载,即遍历数据并更新可视化器

但是程序继续执行而不等待 SwingWorker 的响应...我想尝试 invokeAndWait() 以便程序等待,但是网络本身 运行 EDT,所以它会导致程序崩溃。

我应该怎么做?

P.S。 我想指出的是,当我不创建设置 class,并从控件 class 中的主要方法创建网络时,一切似乎都正常...

发布的代码不是 mcve,因为 prepare 从未被调用过。 Network 执行了一个阻塞 EDT 的长进程。一旦这个过程被调用,它后面的语句直到长过程结束才被执行。
这个 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仅在计数结束后才可见。
将执行顺序更改为

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

导致 settings 在执行计数之前显示。
然而,这不是解决此问题的正确方法。它被张贴来解释问题。
不应在 EDT 上调用长进程。正如 Fracool 所建议的那样,正确的解决方案是使用 SwingWorker 将长过程从 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);
    }
}

另请注意 Andrew Thompson 发布的 link。

好的!感谢 c0der 的回答,以及一些坚持,我设法让它工作。
我试图创建两个 JFrame,第一个用于神经网络的设置,第二个用于它学习的视觉过程。

问题是第二个 JFrame 仅在学习阶段结束时显示图形。 这是因为它 运行 EDT 线程上的繁重工作,因此 EDT 在完成数据循环之前不会更新。
由于 c0der 和 Frakcool 使用 SwingWorker 的建议解决了这个问题。

这是我的开头:

接收到设置后,我们创建一个网络并展示它,将繁重的工作移交给一个SwingWorker:

public Network(int amountOfIterations) {
    graph = new JFrame();
    vis = new Visualiser();
    graph.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    graph.getContentPane().add(vis);
    graph.setSize(1920, 1080);
    graph.setTitle("Graph");
    graph.pack();
    graph.setVisible(true);

    for(int i = 0; i < iterations; i++) {
        new train(i).execute();
        System.out.println(i);
    }
}

class train extends SwingWorker<Void,Void> {

    int i;
    public train(int i) {
        this.i = i;
    }

    @Override
    public Void doInBackground() {
        //Do some heavy work
        int x = 0;
        for(int y = 0; y < 10000000; y++) {
            x = x + y;
        }
        vis.iterated = i;
        vis.repaint();
        System.out.println(i + "  " + x);

        return null;
    }
}

我遇到的问题是我将 SwingWorker 的迭代循环 out。因此,网络不断创建 new SwingWorker。相反,我必须做的是:

    public Network(int amountOfIterations) {
    graph = new JFrame();
    vis = new Visualiser();
    graph.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    graph.getContentPane().add(vis);
    graph.setSize(1920, 1080);
    graph.setTitle("Graph");
    graph.pack();
    graph.setVisible(true);
    new train(amountOfIterations).execute();
}

class train extends SwingWorker<Void,Void> {

    int iterations;
    public train(int amountOfIterations) {
        iterations = amountOfIterations;
    }

    @Override
    public Void doInBackground() {
        for(int i = 0; i < iterations; i++) {
            //Do some heavy work
            int x = 0;
            for(int y = 0; y < 10000000; y++) {
                x = x + y;
            }
            vis.iterated = i;
            vis.repaint();
            System.out.println(i + "  " + x);
        }
        return null;
    }
}