当 while(true) 在线程中循环时 JFrame 冻结
JFrame freezes when while(true) looping in thread
我简化了我的代码与大家分享。现在它有 3 类。 JFrame、JInternalFrame 和一个线程。 JFrame 创建 JInternalFrame,JInternalFrame 创建线程。我的线程中的构造函数需要一个 JInternalFrame 实例来处理它的按钮。
因此,在我创建了我的 InternalFrame 的接口之后,我创建并启动了我的线程。不幸的是,整个 JFrame 冻结,代码将完全保留在线程中。我已经尝试摆脱线程中的 while(true) 循环。然后 JFrame 仅冻结我的睡眠功能所需的时间。
长话短说:如何让线程实际上 运行 并行?没有我的主代码等待线程中的任何睡眠时间或类似的东西。
这是我的 3 类。对于任何愚蠢的菜鸟错误提前道歉。我还在学习中。
JFrame
package nachgestellt;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class Langtons extends JFrame implements ActionListener {
private JDesktopPane desk;
private JPanel panelButtons;
JMenuBar jmb;
JMenu file;
JMenuItem open, exit;
JSlider slider;
int xInt, yInt;
Random randomGenerator = new Random();
JLabel xLabel, yLabel, speed, test;
JButton start, stop, addAnt;
JTextField xField, yField;
public Langtons() {
//Desktop
desk = new JDesktopPane();
getContentPane().add(desk, BorderLayout.CENTER);
xField = new JTextField();
yField = new JTextField();
start = new JButton("Fenster erstellen");
panelButtons = new JPanel();
panelButtons.setLayout(new GridLayout());
;
panelButtons.add(start);
panelButtons.add(xField);
panelButtons.add(yField);
start.addActionListener(this);
add(panelButtons, BorderLayout.NORTH);
setSize(new Dimension(1100, 900));
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Fenster erstellen")) {
xInt = Integer.parseInt(xField.getText());
yInt = Integer.parseInt(yField.getText());
addChild(new kind(this, xInt, yInt), this.getSize().width, this.getSize().height);
}
}
public void addChild(JInternalFrame kind, int x, int y) {
kind.setSize(370, 370);
kind.setLocation(randomGenerator.nextInt(x - kind.getSize().height), randomGenerator.nextInt(y - kind.getSize().height - 100));
kind.setDefaultCloseOperation(JInternalFrame.DISPOSE_ON_CLOSE);
desk.add(kind);
kind.setBackground(Color.blue);
kind.setVisible(true);
}
public static void main(String[] args) {
new Langtons();
}
}
JInternalFrame
package nachgestellt;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.util.ArrayList;
import javax.swing.*;
public class kind extends JInternalFrame {
Langtons hFenster;
static int nr = 0;
JPanel panelButtonsKind;
ArrayList<JButton> jbArray = new ArrayList<JButton>();
JPanel panelSpielfeld;
int posAmeise, aktuellesIcon;
public kind(Langtons la, int x, int y) {
super("Kind " + (++nr), true, true, true, true);
hFenster = la;
panelSpielfeld = new JPanel();
panelSpielfeld.setLayout(new GridLayout(y, x));
jbArray.add(new JButton());
for (int i = 1; i <= (x * y); i++) {
jbArray.add(new JButton(Integer.toString(i)));
panelSpielfeld.add(jbArray.get(i));
jbArray.get(i).setBackground(Color.WHITE);
}
jbArray.get(((x / 2) * y) - y / 2).setBackground(Color.GREEN);
posAmeise = (((x / 2) * y) - y / 2);
setLayout(new BorderLayout());
panelButtonsKind = new JPanel();
panelButtonsKind.setLayout(new GridLayout(1, 3));
add(panelButtonsKind, BorderLayout.NORTH);
add(panelSpielfeld, BorderLayout.CENTER);
setVisible(true);
this.repaint();
thread a = new thread(this);
a.start();
System.out.println("Test Message After Creation and Start of Thread");
}
public void changeColor() {
if (jbArray.get(posAmeise).getBackground().equals(Color.GREEN))
jbArray.get(posAmeise).setBackground(Color.WHITE);
else
jbArray.get(posAmeise).setBackground(Color.GREEN);
}
}
线程
package nachgestellt;
import java.awt.Color;
public class thread extends Thread {
kind k;
public thread(kind kk) {
this.k = kk;
run();
}
public void run() {
super.run();
while (true) {
if (k.jbArray.get(k.posAmeise).getBackground().equals(Color.GREEN)) {
try {
sleep(1000);
k.changeColor();
System.out.println("Test Message Thread!");
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (k.jbArray.get(k.posAmeise).getBackground()
.equals(Color.WHITE)) {
try {
sleep(1000);
k.changeColor();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
您的代码中最直接的问题是:
public thread(kind kk) {
this.k = kk;
run();
}
- 您不想直接调用
run()
方法。您想在线程上调用 start()
。
- 您不应该从构造函数中启动线程(这会导致问题)
- 您可能应该为这个 class 找到一个比小写线程更好的名称。 (不是说是错误,只是命名不当)。
此外,在您的 运行 方法中,您有:
public void run() {
super.run();
}
超级调用是不必要的,你应该添加一个@Override
注释来提高代码的清晰度:
@Override
public void run() {
//your code
}
Swing 是单线程的并且不是线程安全的,你不应该在事件调度线程中做任何可能阻塞它或 运行 很长一段时间的事情。同样,您永远不应该尝试从 EDT 外部更新 UI。
有关详细信息,请参阅 Concurrency in Swing。
Thread#run
只会在当前线程的上下文中调用 Thread
的 run
方法,这不是特别有用,您应该使用 Thread#start
.
但是,话虽如此,在您的情况下,您应该使用 Swing Timer
而不是 Thread
。计时器将在指定的延迟间隔内设置对已注册 ActionListener
的回调,该回调在 EDT 的上下文中执行,从而可以安全地从内部更新 UI。
有关详细信息,请参阅 How to use Swing Timers
我简化了我的代码与大家分享。现在它有 3 类。 JFrame、JInternalFrame 和一个线程。 JFrame 创建 JInternalFrame,JInternalFrame 创建线程。我的线程中的构造函数需要一个 JInternalFrame 实例来处理它的按钮。 因此,在我创建了我的 InternalFrame 的接口之后,我创建并启动了我的线程。不幸的是,整个 JFrame 冻结,代码将完全保留在线程中。我已经尝试摆脱线程中的 while(true) 循环。然后 JFrame 仅冻结我的睡眠功能所需的时间。
长话短说:如何让线程实际上 运行 并行?没有我的主代码等待线程中的任何睡眠时间或类似的东西。
这是我的 3 类。对于任何愚蠢的菜鸟错误提前道歉。我还在学习中。
JFrame
package nachgestellt;
import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import javax.swing.*;
public class Langtons extends JFrame implements ActionListener {
private JDesktopPane desk;
private JPanel panelButtons;
JMenuBar jmb;
JMenu file;
JMenuItem open, exit;
JSlider slider;
int xInt, yInt;
Random randomGenerator = new Random();
JLabel xLabel, yLabel, speed, test;
JButton start, stop, addAnt;
JTextField xField, yField;
public Langtons() {
//Desktop
desk = new JDesktopPane();
getContentPane().add(desk, BorderLayout.CENTER);
xField = new JTextField();
yField = new JTextField();
start = new JButton("Fenster erstellen");
panelButtons = new JPanel();
panelButtons.setLayout(new GridLayout());
;
panelButtons.add(start);
panelButtons.add(xField);
panelButtons.add(yField);
start.addActionListener(this);
add(panelButtons, BorderLayout.NORTH);
setSize(new Dimension(1100, 900));
setVisible(true);
}
public void actionPerformed(ActionEvent e) {
if (e.getActionCommand().equals("Fenster erstellen")) {
xInt = Integer.parseInt(xField.getText());
yInt = Integer.parseInt(yField.getText());
addChild(new kind(this, xInt, yInt), this.getSize().width, this.getSize().height);
}
}
public void addChild(JInternalFrame kind, int x, int y) {
kind.setSize(370, 370);
kind.setLocation(randomGenerator.nextInt(x - kind.getSize().height), randomGenerator.nextInt(y - kind.getSize().height - 100));
kind.setDefaultCloseOperation(JInternalFrame.DISPOSE_ON_CLOSE);
desk.add(kind);
kind.setBackground(Color.blue);
kind.setVisible(true);
}
public static void main(String[] args) {
new Langtons();
}
}
JInternalFrame
package nachgestellt;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import java.util.ArrayList;
import javax.swing.*;
public class kind extends JInternalFrame {
Langtons hFenster;
static int nr = 0;
JPanel panelButtonsKind;
ArrayList<JButton> jbArray = new ArrayList<JButton>();
JPanel panelSpielfeld;
int posAmeise, aktuellesIcon;
public kind(Langtons la, int x, int y) {
super("Kind " + (++nr), true, true, true, true);
hFenster = la;
panelSpielfeld = new JPanel();
panelSpielfeld.setLayout(new GridLayout(y, x));
jbArray.add(new JButton());
for (int i = 1; i <= (x * y); i++) {
jbArray.add(new JButton(Integer.toString(i)));
panelSpielfeld.add(jbArray.get(i));
jbArray.get(i).setBackground(Color.WHITE);
}
jbArray.get(((x / 2) * y) - y / 2).setBackground(Color.GREEN);
posAmeise = (((x / 2) * y) - y / 2);
setLayout(new BorderLayout());
panelButtonsKind = new JPanel();
panelButtonsKind.setLayout(new GridLayout(1, 3));
add(panelButtonsKind, BorderLayout.NORTH);
add(panelSpielfeld, BorderLayout.CENTER);
setVisible(true);
this.repaint();
thread a = new thread(this);
a.start();
System.out.println("Test Message After Creation and Start of Thread");
}
public void changeColor() {
if (jbArray.get(posAmeise).getBackground().equals(Color.GREEN))
jbArray.get(posAmeise).setBackground(Color.WHITE);
else
jbArray.get(posAmeise).setBackground(Color.GREEN);
}
}
线程
package nachgestellt;
import java.awt.Color;
public class thread extends Thread {
kind k;
public thread(kind kk) {
this.k = kk;
run();
}
public void run() {
super.run();
while (true) {
if (k.jbArray.get(k.posAmeise).getBackground().equals(Color.GREEN)) {
try {
sleep(1000);
k.changeColor();
System.out.println("Test Message Thread!");
} catch (InterruptedException e) {
e.printStackTrace();
}
} else if (k.jbArray.get(k.posAmeise).getBackground()
.equals(Color.WHITE)) {
try {
sleep(1000);
k.changeColor();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
您的代码中最直接的问题是:
public thread(kind kk) {
this.k = kk;
run();
}
- 您不想直接调用
run()
方法。您想在线程上调用start()
。 - 您不应该从构造函数中启动线程(这会导致问题)
- 您可能应该为这个 class 找到一个比小写线程更好的名称。 (不是说是错误,只是命名不当)。
此外,在您的 运行 方法中,您有:
public void run() {
super.run();
}
超级调用是不必要的,你应该添加一个@Override
注释来提高代码的清晰度:
@Override
public void run() {
//your code
}
Swing 是单线程的并且不是线程安全的,你不应该在事件调度线程中做任何可能阻塞它或 运行 很长一段时间的事情。同样,您永远不应该尝试从 EDT 外部更新 UI。
有关详细信息,请参阅 Concurrency in Swing。
Thread#run
只会在当前线程的上下文中调用 Thread
的 run
方法,这不是特别有用,您应该使用 Thread#start
.
但是,话虽如此,在您的情况下,您应该使用 Swing Timer
而不是 Thread
。计时器将在指定的延迟间隔内设置对已注册 ActionListener
的回调,该回调在 EDT 的上下文中执行,从而可以安全地从内部更新 UI。
有关详细信息,请参阅 How to use Swing Timers