我正在制作一个通过阵列显示细胞生长的程序。我已经知道了,所以当我按下开始按钮时,数组在 while(true){} 循环中每 10 秒更新一次。问题是我希望能够通过按下暂停按钮来停止循环,但是在循环中,它不会让我使用任何控件。我需要除了无限循环之外的东西来刷新帧。
我是一个新手,但我现在在一个 java 类中。所以我对语言有一定的把握。
我正在制作一个通过阵列显示细胞生长的程序。我已经知道了,所以当我按下开始按钮时,数组在 while(true){} 循环中每 10 秒更新一次。问题是我希望能够通过按下暂停按钮来停止循环,但是在循环中,它不会让我使用任何控件。我需要除了无限循环之外的东西来刷新帧。
我是一个新手,但我现在在一个 java 类中。所以我对语言有一定的把握。
我建议使用单独的线程来处理数组。确保您使用的是线程安全对象(检查 Java Docs),并且当您想启动时,只需在线程对象上调用 .start() 即可。保留一个指向它的指针,以便您可以通过 setPaused(true) 暂停它
像这样的东西......
class MyArrayUpdater extends Thread {
private volatile boolean enabled = true;
private volatile boolean paused = true;
@Override
public void run() {
super.run();
try {
while (enabled) {
if (!paused) {
// Do stuff to your array here.....
}
Thread.sleep(1);
}
} catch (InterruptedException ex) {
// handle ex
}
}
public void setEnabled(boolean arg) {
enabled = arg;
}
public void setPaused(boolean arg) {
paused = arg;
}
}
您需要的是使用Timer来更改组件的状态(在本例中为细胞生长),然后调用JComponent.repaint()
可以取消此计时器以暂停然后重新启动它,您只需创建一个新计时器:
因此,您可以定义以下两种方法:
private Timer timer;
...
public void startPaiting() {
timer = new Timer();
timer.schedule( new TimerTask(){
public void run(){
changeState();
repaint();
}
},0, 10000 ); // 10 s.
}
public void pause(){
timer.cancel();
}
然后在您的“暂停/恢复”按钮中调用此“暂停/启动”方法:
if( e.getActionCommand().equals("Pause")){
growPanel.pause();
setText("Resume");
} else {
growPanel.startPaiting();
setText("Pause");
}
这是查看它运行的完整源代码:
import javax.swing.*;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.event.*;
import java.util.Timer;
import java.util.TimerTask;
public class Grow {
public static void main( String [] args ) {
JFrame frame = new JFrame();
final GrowPanel growPanel = new GrowPanel();
frame.add( growPanel );
frame.add( new JPanel(){{
add( new JButton("Pause"){{
addActionListener( new ActionListener(){
public void actionPerformed( ActionEvent e ){
if( e.getActionCommand().equals("Pause")){
growPanel.pause();
setText("Resume");
} else {
growPanel.startPaiting();
setText("Pause");
}
}
});
}});}}, java.awt.BorderLayout.SOUTH );
frame.setSize( 400, 300 );
frame.setVisible( true );
}
}
class GrowPanel extends JComponent {
private int x;
private int y;
private Timer timer;
GrowPanel() {
x = 10;
y = 10;
startPaiting();
}
public void startPaiting() {
timer = new Timer();
timer.schedule( new TimerTask(){
public void run(){
changeState();
repaint();
}
},0, 100 ); // or 10000 which is 10 s.
}
public void pause(){
timer.cancel();
}
public void paintComponent( Graphics g ){
g.fillOval( x, y, 10, 10 );
}
private void changeState(){
x+=10;
if( x >= 400 ) {
y+=10;
x = 0;
}
if( y >= 300 ){
y = 10;
}
}
}
如果这些“按钮”是 Swing 按钮,那么执行此操作的方法是:让 Start 按钮创建一个新的 javax.swing.Timer 对象,该对象每 10 秒更新一次。然后让暂停按钮停止该计时器。
您想在线程中运行模拟(查找可运行接口)。然后您可以将消息传递给该线程以暂停、继续和停止。
我个人更喜欢使用classTimer
而不是Thread
or Thread.sleep()
。计时器类处理定期运行代码和取消它。
您的代码如下所示:
TimerTask myTask = new TimerTask() {
public void run() {
// here goes my code
}
};
Timer timer = new Timer();
timer.schedule(myTask, 0 /*starts now*/, 10 * 1000 /* every 10 seconds */);
// whenever you need to cancel it:
timer.cancel();
是的。听起来您正在事件调度程序线程上进行绘图。事件(按钮按下)永远没有机会被调用,因为您从未从上次调用它时返回控制权......
您正在寻找的是多线程。将数据处理放在第二个线程中,异步运行,并使用主线程检查用户输入。
当然,这也可能需要使用信号量在两个线程之间进行通信。你在哪个级别的班级 - 你已经涵盖了这两个主题吗?
看看 wait() / notify() 机制。简而言之,一个线程可以等待 10 秒,但仍然会被通知发生了外部事件,
处理此问题的另一种方法是使用作业的BlockingQueue。