Java 让 GUI 等待一个定时器
Java make GUI wait for a timer
我只是想让这个程序等待一个计时器。我只想让程序暂停两秒钟。我想让这个程序做的是显示 "Start," 等待两秒钟直到计时器完成,然后显示 "Start, Finished Waiting, Finished." 如何让这个程序等待计时器完成?我相信它目前在一个单独的线程中创建计时器,而不是暂停主线程,所以它显示,"Start, Finished" 然后等待两秒钟然后显示 "Start, Finished, Finished Waiting." 这不是我想要的东西的顺序发生在,当 运行 一个 GUI 并找到 none 时,我到处寻找一个简单的计时器示例。感谢您的帮助,这是代码:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;
public class GUI extends JFrame {
private static final long serialVersionUID = 3560258176733156660L;
public static void main(String[] args) {
new GUI().setVisible(true);
}
private Timer timer;
private JTextArea area;
private String text;
public GUI() {
setLayout(null);
setSize(500, 120);
setTitle("Timer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
text = "";
area = new JTextArea(text);
area.setBounds(0, 0, 500, 120);
add(area);
doThings();
}
public void doThings() {
text += "Start, ";
area.setText(text);
// Want program to wait for two seconds
waitForTwoSeconds();
text += "Finished ";
area.setText(text);
}
public void waitForTwoSeconds() {
timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
text += "Finished Waiting, ";
area.setText(text);
timer.stop();
}
});
timer.start();
}
}
在调用 waitForTwoSeconds
之后获取代码并将其放入 actionPerformed
方法中...
public void doThings() {
area.setText("Start, ");
// Want program to wait for two seconds
waitForTwoSeconds();
}
public void waitForTwoSeconds() {
timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
area.append("Finished Waiting, ");
area.append("Finished ");
timer.stop();
}
});
timer.setRepeats(false);
timer.start();
}
这将导致 Finished Waiting, Finished
在您单击按钮 2 秒后附加到 JTextArea
...
您不想在事件调度线程的上下文中执行任何长时间的 running/blocking 操作,这会使您的程序看起来像挂起,因为它已经挂起。
查看,Concurrency in Swing and How to use Swing Timers了解更多详情
已更新...
Swing(和大多数 UIs)是事件驱动的,也就是说,某事发生了,你就响应它。例如,对于 Timer
,计时器触发并且您响应了该事件。你不能在 Event Dispatching Thread 中 block/wait,它只会导致 UI 停止响应和绘制,这就是框架的工作方式,你可以学会忍受它或继续对此感到沮丧(记住,想要某样东西和让它发挥作用是两件不同的事情)
但是,您可以做一些事情,Timer
是一个例子,另一个是 SwingWorker
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
public TestPane() {
setLayout(new BorderLayout());
ta = new JTextArea(10, 20);
JButton btn = new JButton("Make it so");
add(new JScrollPane(ta));
add(btn, BorderLayout.SOUTH);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
btn.setEnabled(false);
ta.append("Start, ");
SwingWorker<String, String> worker = new SwingWorker<String, String>() {
@Override
protected String doInBackground() throws Exception {
Thread.sleep(2000);
publish("Finished waiting, ");
return null;
}
@Override
protected void process(List<String> chunks) {
for (String text : chunks) {
ta.append(text);
}
}
@Override
protected void done() {
ta.append("Finished");
btn.setEnabled(true);
}
};
worker.execute();
}
});
}
}
}
这基本上是在后台线程中等待两秒钟,然后(通过 publish
/process
方法)打印 "Finished Waiting",然后在 doInBackground
returns, done
被(最终)调用并且 "Finished" 被打印出来。
这一切都已完成,以便 UI 更新发生在事件调度线程的上下文中,满足 Swing 的单线程要求
Ok, so I guess my question should really look like this then:
How do i make the program wait until the waitForTwoSeconds() method is complete before doing area.append("Finished "); ? This is really what I want to accomplish.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;
public class GUI extends JFrame {
private static final long serialVersionUID = 3560258176733156660L;
public static void main(String[] args) {
new GUI().setVisible(true);
}
private Timer timer;
private JTextArea area;
public GUI() {
setLayout(null);
setSize(500, 120);
setTitle("Timer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
area = new JTextArea("");
area.setBounds(0, 0, 500, 120);
add(area);
doThings();
}
public void doThings() {
area.setText("Start, ");
// Want program to wait for two seconds
waitForTwoSeconds();
// Don't want to do this until waitForTwoSeconds() has finished...
area.append("Finished ");
}
public void waitForTwoSeconds() {
timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
area.append("Finished Waiting, ");
timer.stop();
}
});
timer.setRepeats(false);
timer.start();
}
}
我只是想让这个程序等待一个计时器。我只想让程序暂停两秒钟。我想让这个程序做的是显示 "Start," 等待两秒钟直到计时器完成,然后显示 "Start, Finished Waiting, Finished." 如何让这个程序等待计时器完成?我相信它目前在一个单独的线程中创建计时器,而不是暂停主线程,所以它显示,"Start, Finished" 然后等待两秒钟然后显示 "Start, Finished, Finished Waiting." 这不是我想要的东西的顺序发生在,当 运行 一个 GUI 并找到 none 时,我到处寻找一个简单的计时器示例。感谢您的帮助,这是代码:
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;
public class GUI extends JFrame {
private static final long serialVersionUID = 3560258176733156660L;
public static void main(String[] args) {
new GUI().setVisible(true);
}
private Timer timer;
private JTextArea area;
private String text;
public GUI() {
setLayout(null);
setSize(500, 120);
setTitle("Timer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
text = "";
area = new JTextArea(text);
area.setBounds(0, 0, 500, 120);
add(area);
doThings();
}
public void doThings() {
text += "Start, ";
area.setText(text);
// Want program to wait for two seconds
waitForTwoSeconds();
text += "Finished ";
area.setText(text);
}
public void waitForTwoSeconds() {
timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
text += "Finished Waiting, ";
area.setText(text);
timer.stop();
}
});
timer.start();
}
}
在调用 waitForTwoSeconds
之后获取代码并将其放入 actionPerformed
方法中...
public void doThings() {
area.setText("Start, ");
// Want program to wait for two seconds
waitForTwoSeconds();
}
public void waitForTwoSeconds() {
timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
area.append("Finished Waiting, ");
area.append("Finished ");
timer.stop();
}
});
timer.setRepeats(false);
timer.start();
}
这将导致 Finished Waiting, Finished
在您单击按钮 2 秒后附加到 JTextArea
...
您不想在事件调度线程的上下文中执行任何长时间的 running/blocking 操作,这会使您的程序看起来像挂起,因为它已经挂起。
查看,Concurrency in Swing and How to use Swing Timers了解更多详情
已更新...
Swing(和大多数 UIs)是事件驱动的,也就是说,某事发生了,你就响应它。例如,对于 Timer
,计时器触发并且您响应了该事件。你不能在 Event Dispatching Thread 中 block/wait,它只会导致 UI 停止响应和绘制,这就是框架的工作方式,你可以学会忍受它或继续对此感到沮丧(记住,想要某样东西和让它发挥作用是两件不同的事情)
但是,您可以做一些事情,Timer
是一个例子,另一个是 SwingWorker
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.List;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private JTextArea ta;
public TestPane() {
setLayout(new BorderLayout());
ta = new JTextArea(10, 20);
JButton btn = new JButton("Make it so");
add(new JScrollPane(ta));
add(btn, BorderLayout.SOUTH);
btn.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
btn.setEnabled(false);
ta.append("Start, ");
SwingWorker<String, String> worker = new SwingWorker<String, String>() {
@Override
protected String doInBackground() throws Exception {
Thread.sleep(2000);
publish("Finished waiting, ");
return null;
}
@Override
protected void process(List<String> chunks) {
for (String text : chunks) {
ta.append(text);
}
}
@Override
protected void done() {
ta.append("Finished");
btn.setEnabled(true);
}
};
worker.execute();
}
});
}
}
}
这基本上是在后台线程中等待两秒钟,然后(通过 publish
/process
方法)打印 "Finished Waiting",然后在 doInBackground
returns, done
被(最终)调用并且 "Finished" 被打印出来。
这一切都已完成,以便 UI 更新发生在事件调度线程的上下文中,满足 Swing 的单线程要求
Ok, so I guess my question should really look like this then:
How do i make the program wait until the waitForTwoSeconds() method is complete before doing area.append("Finished "); ? This is really what I want to accomplish.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JTextArea;
import javax.swing.Timer;
public class GUI extends JFrame {
private static final long serialVersionUID = 3560258176733156660L;
public static void main(String[] args) {
new GUI().setVisible(true);
}
private Timer timer;
private JTextArea area;
public GUI() {
setLayout(null);
setSize(500, 120);
setTitle("Timer");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLocationRelativeTo(null);
area = new JTextArea("");
area.setBounds(0, 0, 500, 120);
add(area);
doThings();
}
public void doThings() {
area.setText("Start, ");
// Want program to wait for two seconds
waitForTwoSeconds();
// Don't want to do this until waitForTwoSeconds() has finished...
area.append("Finished ");
}
public void waitForTwoSeconds() {
timer = new Timer(2000, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
area.append("Finished Waiting, ");
timer.stop();
}
});
timer.setRepeats(false);
timer.start();
}
}