我有一个窗口,带有开始和停止按钮。开始按钮启动算法,停止按钮应该停止它。我使用SwingWorker
在后台运行算法,通常调用worker.cancel(true)
应该停止算法运行。我还有一个可视化状态的标签,例如如果我按下“停止”,则Labeltext会变为“已停止”,因此问题不在按钮的actionLister上。
我的代码如下所示:
public class MainWindow extends JFrame implements ActionListener, WindowListener
{
// Some code, like generating JFrame, JButtons and other stuff not affencting the task.
Worker worker = new Worker();
public void actionPerformed(ActionEvent e)
{
boolean isStarted = false;
// Start Button
if (e.getSource() == this.buttonStart)
{
if(!isStarted)
{
System.out.println("start");
labelSuccess.setText("Mapping started!");
this.setEnabled(true);
worker.execute();
isStarted = false;
}
}
// Stop Button
if (e.getSource() == this.buttonStop)
{
labelSuccess.setText("Mapping stopped!");
worker.cancel(true);
}
}
class Worker extends SwingWorker<Void, Void> {
@Override
protected Void doInBackground() throws Exception {
if(!isCancelled())
{
mapp();
Thread.sleep(60);
if (isCancelled()) {
System.out.println("SwingWorker - isCancelled");
}
}
return null;
}
}
在此点,按停止按钮只会更改Label-Text,但后台的算法仍在运行。现在这困扰了我很长一段时间,我无法顺利进行。
非常感谢您的帮助,非常感谢。
edit1:我现在在actionPerformed之外生成一个新的worker实例,所以现在每次鼠标点击都没有生成新的Worker。
答案 0 :(得分:2)
如果您在while
课程的if
方法上使用doInBackground()
而不是Worker
,则可以解决您的问题。您必须退出while
循环mapp()
,因为您只想调用它一次。你应该这样做:
class Worker extends SwingWorker<Void, Void> {
@Override
protected Void doInBackground() throws Exception {
mapp();
while(!isCancelled()){
Thread.sleep(60);
}
System.out.println("SwingWorker - isCancelled");
return null;
}
此link可能有助于了解如何使用SwingWorker
。
修改强>
正如您在this或this等其他问题上看到的那样,使用SwingWorker
管理cancel
方法存在一些问题,因为此方法尝试取消执行此任务。如果任务已经完成,已被取消,或因某些其他原因无法取消 ,如Oracle解释,以及那些“其他”,此尝试将失败原因“在我发布的链接上进行了讨论。
您可以直接使用Threads
解决问题。你的代码是这样的:
public class MainWindow extends JFrame implements ActionListener, WindowListener
{
// Some code, like generating JFrame, JButtons and other stuff not affencting the task.
final Thread th1 = new Thread(new Runnable() {
@Override
public void run() {
mapp();
}
});
public void actionPerformed(ActionEvent e)
{
boolean isStarted = false;
// Start Button
if (e.getSource() == this.buttonStart)
{
if(!isStarted)
{
System.out.println("start");
labelSuccess.setText("Mapping started!");
this.setEnabled(true);
th1.start();
isStarted = false;
}
}
// Stop Button
if (e.getSource() == this.buttonStop)
{
labelSuccess.setText("Mapping stopped!");
th1.stop();
}
}
此解决方案使用的方法stop()
已弃用,但可以使用。我尝试过使用interrupt()
,但我不知道为什么线程会运行直到完成mapp()
的执行。显然,使用stop()
并不是最好的方法,但它可以在mapp()
执行完成之前停止执行。
我建议您详细了解SwingWorker
,Thread
和Task
,以找到问题的最佳解决方案。
答案 1 :(得分:1)
你的问题是worker中没有循环:如果你想使用标志取消进程,那个进程应该不时地检查标志,所以如果你的方法Worker.mapp()必须被停止,检查那里的标志,不是在调用它之前和之后。