Java Swing取消无限循环
我在Swing中遇到了无限循环问题。做了一些研究,遇到了SwingWorker线程,但不确定如何实现它们。我拼凑了一个简单的程序来说明这个问题。一个按钮启动无限循环,我希望另一个按钮停止它,但当然,由于Swing单线程问题,另一个按钮已冻结。代码如下,感谢您的帮助:-Java Swing取消无限循环,java,swing,Java,Swing,我在Swing中遇到了无限循环问题。做了一些研究,遇到了SwingWorker线程,但不确定如何实现它们。我拼凑了一个简单的程序来说明这个问题。一个按钮启动无限循环,我希望另一个按钮停止它,但当然,由于Swing单线程问题,另一个按钮已冻结。代码如下,感谢您的帮助:- public class Model { private int counter; private boolean go = true; public void go() { co
public class Model
{
private int counter;
private boolean go = true;
public void go()
{
counter = 0;
while(go)
{
counter++;
System.out.println(counter);
}
}
public int getCounter()
{
return counter;
}
public void setGo(boolean value)
{
this.go = value;
}
}
public class View extends JFrame
{
private JPanel topPanel, bottomPanel;
private JTextArea messageArea;
private JButton startButton, cancelButton;
private JLabel messageLabel;
private JScrollPane scrollPane;
public View()
{
setSize(250, 220);
setTitle("View");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
topPanel = new JPanel();
bottomPanel = new JPanel();
messageArea = new JTextArea(8, 20);
messageArea.setEditable(false);
scrollPane = new JScrollPane(messageArea);
messageLabel = new JLabel("Message Area");
topPanel.setLayout(new BorderLayout());
topPanel.add(messageLabel, "North");
topPanel.add(scrollPane, "South");
startButton = new JButton("START");
cancelButton = new JButton("CANCEL");
bottomPanel.setLayout(new GridLayout(1, 2));
bottomPanel.add(startButton);
bottomPanel.add(cancelButton);
Container cp = getContentPane();
cp.add(topPanel, BorderLayout.NORTH);
cp.add(bottomPanel, BorderLayout.SOUTH);
}
public JButton getStartButton()
{
return startButton;
}
public JButton getCancelButton()
{
return cancelButton;
}
public void setMessageArea(String message)
{
messageArea.append(message + "\n");
}
}
public class Controller implements ActionListener
{
private Model theModel;
private View theView;
public Controller(Model model, View view)
{
this.theModel = model;
this.theView = view;
view.getStartButton().addActionListener(this);
view.getCancelButton().addActionListener(this);
}
public void actionPerformed(ActionEvent ae)
{
Object buttonClicked = ae.getSource();
if(buttonClicked.equals(theView.getStartButton()))
{
theModel.go();
}
else if(buttonClicked.equals(theView.getCancelButton()))
{
theModel.setGo(false);
}
}
}
public class Main
{
public static void main(String[] args)
{
Model model = new Model();
View view = new View();
Controller controller = new Controller(model, view);
view.setVisible(true);
}
}
您正在阻止
事件调度线程(EDT)。线程负责处理绘制和其他与UI相关的请求。一旦EDT被阻止,UI将被冻结,因为它无法处理任何事件。有关更多详细信息,请参见教程
考虑使用计时器(),SwingWorker
或辅助后台线程。后台线程可以使用SwingUtilities.invokeLater()
与EDT通信。此机制已在SwingWorker中实现,因此可能更容易使用。这取决于所需的功能 在事件处理中使用start()
和stop()
使用javax.swing.Timer
执行一次go()
工作(可选延迟)。不需要实现任何计时器,就可以轻松地执行,只需在actionPerformed方法中添加两行代码:
public void actionPerformed(ActionEvent ae)
{
Object buttonClicked = ae.getSource();
if(buttonClicked.equals(theView.getStartButton()))
{
theModel.setGo(true); //make it continue if it's just stopped
Thread t = new Thread(new Runnable() { public void run() {theModel.go();}}); //This separate thread will start the new go...
t.start(); //...when you start the thread! go!
}
else if(buttonClicked.equals(theView.getCancelButton()))
{
theModel.setGo(false);
}
}
由于您的Model.go()在一个单独的线程中运行,因此事件调度线程可以自由地执行它的任务,比如再次释放按钮,而不是挂起按钮
有一个陷阱但是,因为运行Model.go()的线程将疯狂运行,它实际上每秒被调用的次数尽可能多
如果您计划实施一些动画或类似内容,则需要:
- 使用计时器
或
- 添加一些到新线程中
使用线程时的示例:
public void go()
{
counter = 0;
while(go)
{
counter++;
System.out.println(counter);
try {
Thread.sleep(1500); //Sleep for 1.5 seconds
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
如您所见,我添加了线程。睡眠(1500)为1500毫秒(1.5秒)。Thread.sleep可能由于某些原因而被中断,因此您必须捕获中断异常
在这种特殊情况下,无需深入讨论如何正确处理中断异常,但如果您对此感到好奇,可以阅读此文。我决定使用SwingWorker线程,下面是更新的控制器类。它做了我需要它做的事情,但我的问题是,它是正确的方式吗?它是干净的代码吗?此外,我还尝试根据注释掉的行将model.go()方法的输出放入视图的文本区域,但没有成功,有人知道怎么做吗
public class Controller implements ActionListener
{
private Model theModel;
private View theView;
private SwingWorker<Void, Void> worker;
public Controller(Model model, View view)
{
this.theModel = model;
this.theView = view;
view.getStartButton().addActionListener(this);
view.getCancelButton().addActionListener(this);
}
public void actionPerformed(ActionEvent ae)
{
Object buttonClicked = ae.getSource();
if(buttonClicked.equals(theView.getStartButton()))
{
theModel.setGo(true);
worker = new SwingWorker<Void, Void>()
{
@Override
protected Void doInBackground()
{
// theView.setMessageArea(theModel.getCounterToString());
return theModel.go();
}
@Override
protected void done()
{
// theView.setMessageArea(theModel.getCounterToString());
}
};
worker.execute();
}
else if(buttonClicked.equals(theView.getCancelButton()))
{
theModel.setGo(false);
}
}
}
public class Model
{
public Void go()
{
counter = 0;
while(go)
{
counter++;
System.out.println(counter);
}
return null;
}
公共类控制器实现ActionListener
{
私有模型;
私人观点;
私人荡秋千工人;
公共控制器(模型、视图)
{
this.theModel=模型;
this.theView=视图;
view.getStartButton().addActionListener(这个);
view.getCancelButton().addActionListener(此);
}
已执行的公共无效行动(行动事件ae)
{
Object buttonClicked=ae.getSource();
if(buttonClicked.equals(theView.getStartButton()))
{
setGo模型(true);
工人=新的SwingWorker()
{
@凌驾
受保护的Void doInBackground()
{
//view.setMessageArea(model.getCounterToString());
返回model.go();
}
@凌驾
受保护的void done()
{
//view.setMessageArea(model.getCounterToString());
}
};
worker.execute();
}
else if(buttonClicked.equals(theView.getCancelButton()))
{
setGo模型(false);
}
}
}
公共类模型
{
公开作废go()
{
计数器=0;
while(go)
{
计数器++;
系统输出打印项次(计数器);
}
返回null;
}