Чтобы вызватьLater () или нет - PullRequest
       24

Чтобы вызватьLater () или нет

2 голосов
/ 21 февраля 2012

Я писал пример для демонстрации использования SwingUtilities.invokeLater (). Я пришел к выводу, что этот простой пример (с кодом), который я написал, не гарантирует использование invokeLater (). Я сталкивался с тем, что были времена, когда мне нужно было использовать invokeLater (), но я забыл, где и когда я использовал. Я также понимаю, что в потоке, не поддерживающем EDP, я должен использовать invokeLater (), но в моем случае мне это, похоже, не нужно, и все работало нормально. Я надеялся, что кто-нибудь посоветует мне, почему мне не нужно использовать invokeLater () в этом фрагменте кода. Я надеюсь, что в моем коде витрины нет ошибки.

Кстати, я использую JDK 1.6 / 1.7 в Linux и Windows.

Спасибо.

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());
    }
}

1 Ответ

3 голосов
/ 21 февраля 2012

Здесь есть две ситуации, когда вы должны использовать invokeLater.

  1. Создание пользовательского интерфейса.
  2. Обновление JLabel.

Все создание пользовательского интерфейса должно быть сделано в EDT. В древние времена Swing говорили, что вы можете делать любое создание до show или setVisible(true) в главном потоке, так как до этого момента не возникало проблем с потоками. Так как это было и было сомнительно , то теперь не рекомендуется ; это может сработать - очевидно, как и в вашем случае - но нет гарантии.

Вам повезло, что setText в JLabel ведет себя хорошо в этом контексте. Поскольку API не гарантирует, что метод является потокобезопасным, вы должны вызывать этот метод в EDT, как и любой другой вызов методов Swing.

Итак, в заключение: у вас есть простой пример, который, кажется, работает - потому что он прост, и вам повезло. Не полагайтесь на такие «тесты», а на документацию. Если ваша витрина включает в себя представление кода, то вам необходимо перевести вызовы в EDT, чтобы не ошибаться.

Я не понимаю, почему ваш код не должен "гарантировать" использование invokeLater.

...