为什么ActionListener中的更改不会立即生效?

时间:2014-11-16 13:06:27

标签: java swing concurrency awt actionlistener

这是我的代码:

public MyClass() {
    JButton btnNext;
    private void initComponents() {
        btnNext = new javax.swing.JButton();
        btnNext.setText("Lanjut");
        btnNext.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btnNextActionPerformed(evt);
            }
        });
    }

    private void btnNextActionPerformed(java.awt.event.ActionEvent evt) {
        btnNext.setText("Loading...");
        callingFunction();
    }
}

注意:callingFunction()是一个需要很长时间才能执行的函数。

我的问题是我的按钮文字将更改为"正在加载..."只有在调用函数()完成后才能完成。

如何将btnNext文本更改为"正在加载..."立即?

1 个答案:

答案 0 :(得分:5)

按钮不会被重新绘制,直到控件返回到Swing事件队列。在事件派发线程上调用该函数会阻塞事件队列。

作为一种解决方法,请告诉它稍后运行该功能(只要它重绘完了东西):

在Java 8 +中:

EventQueue.invokeLater(() -> callingFunction());

在旧Java中:

EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        callingFunction();
    }
});

请注意,在该函数运行时,这仍会产生阻止与GUI进一步交互的副作用。如果要在后台线程中运行长任务以使GUI保持交互,请使用SwingWorker。一个最小的示例,假设callingFunction返回您想要用于更新显示的类型String(或其他)的某些结果:

new SwingWorker<String,Void>() {
    @Override
    protected String doInBackground() throws Exception {
        // called on a background thread
        return callingFunction();
    }

    @Override
    protected void done() {
        // called on the event dispatch thread after the work is done
        String result;
        try {
            result = get();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        // do something with the result ...
        someTextField.setText(result);
    }
}.execute();