使ActionListener在完成执行整个ActionListener之前提交对JButton的更改

时间:2014-06-26 16:24:33

标签: java user-interface jbutton actionlistener

在Java中,我使用ActionListener作为JButton数组。我希望ActionListener的早期部分将新的ImageIcon设置为JButton,该更改立即显示,然后接近ActionListener的末尾,以便在第二次长时间延迟后将JButton的ImageIcon设置为null

我的问题是,在ActionListener完全完成之前,JButton中发生的任何更改都不会显示在GUI窗口中,这使得JButton的ImageIcon中的更改无法察觉。有没有办法让ActionListener在完成整个ActionListener的执行之前提交对JButton的更改,或者我应该以不同的方式进行此操作?

2 个答案:

答案 0 :(得分:2)

发生这种情况的原因:

Swing重新绘制同一线程(EDT)上的按钮,运行ActionListener。因此,如果它正在执行你ActionListener,它就无法重绘,因为线程很忙 - 就这么简单。您可能已经注意到,当您的动作监听器正在执行时,您也无法正确移动框架等(GUI冻结)。

解决方案:

在EDT之外移动重型处理。它无论如何也不属于那里。你可能已经猜到了 - 使用后台线程/线程池。一个很好的指南是Swing tutorial for concurrency

注意:

如指南中所描述的那样,您不希望修改EDT之外的组件。因此,最简单的策略是使Runnable在后​​台线程上执行,启动它,更改按钮上的图片并返回而不等待任务完成。

public void actionPerformed(ActionEvent ae) {
    Runnable task = new Runnable() {..};
    executor.execute(task);
    button.setIcon(newIcon);
    return;
}

请注意,这并不会锁定任务的EDT,因此允许Swing立即更改图片。

这当然意味着用户不知道任务是否已经完成(如果有任何例外)!它毕竟是在后台!因此,执行会有一个额外的状态:GUI响应和非冻结,按钮被更改,但任务仍在运行。在大多数应用程序中,这可能是一个问题(用户将垃圾邮件按钮或您的后台任务可能交错)。在这种情况下,您可能希望使用SwingWorker进行"处理"国家也是如此。

public void actionPerformed(ActionEvent ae) {
    new TaskWorker().execute();
    button.setIcon(loadingIcon); //Shows loading. Maybe on button, maybe somewhere else.
    return;
}

private class TaskWorker extends SwingWorker<Void, T> {
    public Void doInBackground() {
        //Do your task in the background here
    }
    protected void done() {
        try {
            get();
            button.setIcon(doneIcon);
        catch (<relevant exceptions>) {
            button.setIcon(failedIcon);
        }
    }
}  

done()完成时,doInBackground()在EDT上被称为

答案 1 :(得分:0)

如果您有线程池,则可以从线程池创建新的线程或线程。然后让任务在一个单独的Thread上运行,以便ActionListener立即返回。然后在另一个线程中,您执行代码并重新绘制按钮。顺便说一下,我不确定它是否会起作用。