Frage

I was writing an example to showcase the usage of SwingUtilities.invokeLater(). I came to realize this simple example (code included) I have written didn't warranty the use of invokeLater(). I do encounter there were times I needed to use invokeLater() but I forgotten where and when I used. I also understand that in a non EDP thread I should use invokeLater() but in my case I don't seem to need that and it worked fine. I was hoping anyone advise me why I don't need to use invokeLater() in this piece of code. I hope there is no bug in my showcase code.

Btw, I am using JDK 1.6 / 1.7 in Linux and Windows.

Thanks.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class HelloButton {
    public static void main(String[] args) {
        JFrame f = new JFrame();
        f.setLayout(new FlowLayout());
        f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        JSplitPane pane = new JSplitPane();
        f.add(pane);
        final JLabel clickMessage = new JLabel("No Message at " + System.currentTimeMillis());
        pane.setLeftComponent(clickMessage);
        JButton clickMe = new JButton("Click me");
        clickMe.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                threadedIntensiveProcess(clickMessage);
//                intensiveProcess(clickMessage);
            }
        });
        pane.setRightComponent(clickMe);

        f.pack();
        f.setVisible(true);
    }

    static private void threadedIntensiveProcess(final JLabel label)
    {
        new Thread(new Runnable() {
            @Override
            public void run() {
                System.out.println("UI Thread : " + SwingUtilities.isEventDispatchThread());
                intensiveProcess(label);
            }
        }).start();
    }

    static private void intensiveProcess(JLabel label)
    {
        label.setText("was clicked at " + System.currentTimeMillis());
        for (int i = 0; i < 3; i++)
        {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            label.setText("was updated at " + System.currentTimeMillis());
        }
        System.out.println(label.getText());
    }
}
War es hilfreich?

Lösung

There are two situations here where you should use invokeLater.

  1. The creation of the UI.
  2. The update of the JLabel.

The whole creation of the UI should be done in the EDT. In ancient Swing times it was said that you could do any creation until show or setVisible(true) in the main thread as no threading issues could arise up to that point. As this is and was doubtful this is now discouraged; it may work -obviously, as in your case- but there is no guarantee.

You are lucky that setText in JLabel behaves well in this context. As it is not guaranteed by the API that the method is threadsafe you should call this method in the EDT like any other call to Swing methods.

So, in conclusion: You have a simple example that seems to work - because it is simple and you are lucky. Don't rely on such "tests" but on the documentation. If your showcase involves the presentation of the code then you have to move the calls to the EDT for not being wrong.

I don't understand why your code shouldn't "warrant" the use of invokeLater.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top