我正在尝试随机生成一个字符串并不断更新JTextArea。我知道程序在无限循环中的runTest()方法中挂起。我正在尝试循环并显示此结果,直到用户点击停止按钮。有什么建议?感谢
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JTextArea;
import javax.swing.SwingUtilities;
import java.awt.BorderLayout;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class MyApplication extends JFrame {
private JTextArea textArea;
private JButton b;
private String toChange = "";
// Called from non-UI thread
private void runQueries() {
while (true) {
runTest();
updateProgress();
}
}
public void runTest() {
while (true) {
if (toChange.length() > 10) {
toChange = "";
}
Random rand = new Random();
toChange += rand.nextInt(10);
}
}
private void updateProgress() {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
textArea.append(toChange);
}
});
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
MyApplication app = new MyApplication();
app.setVisible(true);
}
});
}
private MyApplication() {
this.setLayout(null);
this.setResizable(false);
this.setLocation(100, 100);
this.setSize(900, 600);
final Panel controlPanel = new Panel();
controlPanel.setLayout(new BorderLayout());
controlPanel.setSize(600, 200);
controlPanel.setLocation(50, 50);
setDefaultCloseOperation(this.EXIT_ON_CLOSE);
textArea = new JTextArea("test");
textArea.setSize(100, 100);
textArea.setLocation(200, 200);
this.add(textArea);
JButton b = new JButton("Run query");
b.setSize(100, 75);
b.setLocation(100, 50);
this.add(b);
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
Thread queryThread = new Thread() {
public void run() {
runQueries();
}
};
queryThread.start();
}
});
}
}
答案 0 :(得分:3)
int initialDelay = 1000; // start after 1 seconds
int period = 1000; // repeat every 1 seconds
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
if (toChange.length() > 10) {
toChange = "";
}
Random rand = new Random();
toChange += rand.nextInt(10);
};
timer.scheduleAtFixedRate(task, initialDelay, period);
你会想要像我刚刚做的那样的东西。否则,您只是冻结线程,因此永远不会调用updateProgress();
。
就此而言,为什么你甚至需要在while (true)
方法中使用runTest()
循环?它始终由runQueries()
中的while true循环运行和更新,这意味着while (true)
循环似乎没有意义。
澄清: 我说你应该把你的runTest()和updateProgress()放在一个延迟的任务中,而不是一个真正的循环 - 否则,你只是把它们放在同一个线程中来阻止另一个任务。
但是,更改此功能也可以解决问题:
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
int initialDelay = 100; // start after 0.1 seconds
int period = 100; // repeat every 0.1 seconds
{
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
runTest();
};
timer.scheduleAtFixedRate(task, initialDelay, period);
}
{
Timer timer = new Timer();
TimerTask task = new TimerTask() {
public void run() {
updateProgress();
};
timer.scheduleAtFixedRate(task, initialDelay, period);
}
}
});
}
和runTest()..
public void runTest() {
if (toChange.length() > 10) {
toChange = "";
}
Random rand = new Random();
toChange += rand.nextInt(10);
}
和updateProgress()..
private void updateProgress() {
textArea.append(toChange);
}
请注意,我在SO编辑器中输入了代码,而不是在IDE中。对于任何语法错误,我们深表歉意。
答案 1 :(得分:1)
我不能强调的最重要的事情之一是Java中的所有GUI元素都应该在EventDispatchThread上运行,如果不这样做会导致不可预测和错误的行为。
在此处阅读:https://docs.oracle.com/javase/tutorial/uiswing/concurrency/dispatch.html
从我现在的代码中可以看出,你通过在一个不变的循环中冻结它来锁定你的应用程序。
您要做的是创建一个单独的线程,在创建时不断更新EDT中的TextArea但保持在主应用程序中引用此线程。 一旦用户按下按钮(这将在EDT上),它应该告诉你的主线程杀死你的单独线程导致更新停止。
如果您遇到困难,请随时提出更详细的步骤。
答案 2 :(得分:0)
试试这个。
private void runQueries() {
while (!stop) {
runTest();
updateProgress();
}
}
当你想要的时候, make stop
是真的,例如点击停止按钮。然后
public void runTest() {
while (true) {
if (toChange.length() > 10) {
toChange = "";
break;
}
Random rand = new Random();
toChange += rand.nextInt(10);
}
}
如果你不打破循环,你的updateProgress
就不会打电话......