Радиокнопка не меняет состояние сразу

В нашем проекте мой товарищ по команде заметил необычное поведение переключателя, когда внутри прослушивателя действий есть вызов SwingUtilites.invokeLater. Архитектура прослушивателя действий не позволяет избежать этого вызова, т.к. он предназначен для запуска другого потока, а затем происходит переключение обратно на поток AWT.

Есть ли способ исправить это? Я имею в виду изменение состояния отображаемого компонента.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;

public class RadioButtonTest {

public static void main(String[] args) {
    try {
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException
            | UnsupportedLookAndFeelException e1) {
        e1.printStackTrace();
    }
    JFrame frame = new JFrame();
    JPanel panel = new JPanel();
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.setSize(200, 200);
    frame.add(panel);
    ButtonGroup group = new ButtonGroup();
    JRadioButton b1 = new JRadioButton("Button 1");
    final JRadioButton b2 = new JRadioButton("Button 2");
    b2.addActionListener(new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            Runnable action = new Runnable() {

                @Override
                public void run() {
                    try {
                        Thread.sleep(2500);
                    } catch (InterruptedException e) {
                        Thread.currentThread().interrupt();
                        e.printStackTrace();
                    }
                }
            };
            SwingUtilities.invokeLater(action);
        }
    });
    group.add(b1);
    group.add(b2);
    panel.add(b1);
    panel.add(b2);

    frame.setVisible(true);
} 
}

person yu.pitomets    schedule 18.12.2014    source источник


Ответы (2)


Используйте SwingWorker, попробуйте этот код:

 public void actionPerformed(ActionEvent arg0) {
       SwingWorker<Object,Object> sw = new SwingWorker<Object,Object>()
       {
            @Override
            protected Object doInBackground() throws Exception
            {
                try {
                     Thread.sleep(2500);
                 } catch (InterruptedException e) {
                     Thread.currentThread().interrupt();
                     e.printStackTrace();
                 }
                 return null;
            }
        };
        sw.execute();
}

SwingWorker выполняется в отдельном рабочем потоке, который вызывается потоком диспетчера событий путем вызова метода execute. Метод SwingUtilities.invokeLater просто навязывает метод run для асинхронного выполнения в потоке диспетчеризации событий, поэтому вызов Thread.sleep внутри него замораживает поток диспетчеризации событий, что влияет на графический интерфейс.

person Naruto Biju Mode    schedule 18.12.2014

Похоже, вы хотите избежать многократного запуска длительной фоновой задачи. Вместо JRadioButton используйте родительский элемент JToggleButton и задайте для его имени и действия значение Отмена при запуске фоновой задачи. Future, например SwingWorker, делает это удобным. Связанный пример с использованием JButton можно увидеть здесь.

person trashgod    schedule 18.12.2014