多个 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;
}
}
这里的问题是,在通过设置 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;
}
}