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

smf*_*ftr 0 java concurrency swing 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();
    }
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Boa*_*ann 5

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

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

在Java 8+中:

EventQueue.invokeLater(() -> callingFunction());
Run Code Online (Sandbox Code Playgroud)

在旧的Java中:

EventQueue.invokeLater(new Runnable() {
    @Override
    public void run() {
        callingFunction();
    }
});
Run Code Online (Sandbox Code Playgroud)

请注意,这仍然会产生在该函数运行时阻止与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();
Run Code Online (Sandbox Code Playgroud)