Вопрос по java, swing, thread-sleep, event-dispatch-thread – Спящий поток внутри метода actionPerformed

3

Прежде всего, я хочу сказать, что яЯ знаю, что этот подход не так, поэтому яЯ задаю этот вопрос из-за чистого любопытства. Допустим, у меня есть свинг-приложение, подобное этому:

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

import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class ThreadSleeping {
    JFrame frame = new JFrame();
    JPanel panel = new JPanel();
    JButton button = new JButton("Load");
    JLabel label = new JLabel();

    public ThreadSleeping() {
        panel.add(button);

        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                label.setIcon(new ImageIcon(
                        "C:/Users/Public/Pictures/Sample Pictures/Tulips.jpg"));
                System.out.println("Tulips painted");
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                label.setIcon(new ImageIcon(
                        "C:/Users/Public/Pictures/Sample Pictures/Koala.jpg"));
                System.out.println("Koala painted");

            }
        });

        frame.add(panel, BorderLayout.NORTH);
        frame.add(label, BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(1024, 768);
        // frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ThreadSleeping();
            }
        });
    }
}

В основном, когда я нажимаюLoad Кнопка Я ожидаю, чтоTulips.jpg изображение отображается, затем графический интерфейс останавливается на 2 секунды, и после этого я ожидаю, чтоKoala.jpg изображение отображается. Но происходит следующее: я нажимаю на кнопку, графический интерфейс останавливается на 2 секунды иKoala.jpg дисплеи. нетTulips.jpg до этого. Но меня смущает то, чтоSystem.out.println("Tulips painted"); а такжеSystem.out.println("Koala painted");, Поэтому, когда я нажимаю на кнопку, она печатает "Тюльпаны нарисованные и через 2 секундыКоала нарисовала, Может кто-нибудь сказать мне, что здесь происходит? С уважением.

Вам нужно вернуться изactionPerformed так что качели могут обновить графический интерфейс. enobayram
@kleopatra - я не согласен от всего сердца. Это'очень познавательно, чтобы понятьЗачем что-то плохая практика, гораздо ценнее, чем просто слушать, как другие говорят "Дон»т!», Если ты "просто играй по правилам вы'никогда ничего не достигнешь - пойми, почему существуют правила, и используй эти знания в своих интересах. dimo414
@ dimo414 ты прав, должен был пропустить последнее предложение - быть большим поклонникомЗачем себя ;-) kleopatra
если вы спите, это приведет к непредсказуемым последствиям. Это неНе имеет смысла пытаться что-то в него интерпретировать. Просто играйте по правилам и вкладывайте свое время и усилия во что-то полезное :-) kleopatra

Ваш Ответ

2   ответа
3

потому что вы программно заморозили ouf Swing GUI, но есть / aren 'другое обновление (я), другой JComponent (s)

doens'Это работает в том случае, если есть несколько других обновленных в Swing GUI, Thread.sleep (int) freeze Thread Dispatch Thread,

по умолчанию все обновленияJComponents XxxModels никогда не будет виден наJComponents view

пример пока сон не кончилсяпотеряю все обновленное в GUI

Я был только смущен, почему это работает. Спасибо! :) Branislav Lazic
важными являются Native OS, используемые Look и Feel и методы, объявленные в API как безопасные для потоков, затем по умолчанию WinXP, Java6, MetalLoookAndFeel и методы setText (), append () ... работают по умолчанию, но в Java7 были изменены некоторые из этих логика mKorbel
2

если вы спите, это приведет к непредсказуемым последствиям.

непредсказуемый в том смысле, что выМожно'не знаю что будет или нет. Все, что мы можем сделать, это угадать ...

Техническая причина в том, что большинство обновлений пользовательского интерфейса нене может произойти сразу, но запланировано: мы можемна самом деле не знаю чтожду в очереди позади нас. Помни это'только одна полоса, и в действииМы, которые сидим в нем.

По образовательным причинам приведенный ниже код является исходным кодом с парой строк, которые нужно удалить / комментировать, чтобы продемонстрировать различные сценарии.

[0] сброс иконки до / после сна: как вы уже заметили, первая непоказать, хотяимущество взят. Техническая причина: визуальное обновление происходит черезlabel.repaint() который запланирован на EDT для последней обработки (как указано в api doc)[1] просматривая api doc, мы замечаем другой метод:paintImmediately(...) который задокументирован, чтобы сделать именно то, что онИмя говорит и разрешено - как мы на EDT - разрешено вызывать. Выглядит как успех, появляется желтый значок.[2] но подождите: находясь в центре границы, метка в любом случае заполняет эту область, независимо от того, есть ли на ней значок. Позволять's попытайтесь поместить это в область, которая требует изменения расположения, как f.i. на юг. Вернуться к квадрату [0], желтый значок не отображается.[3] глядя на источникsetIcon(..) показывает, что макет ... запланирован снова. В квадрате [1] мы узнали, что мы можем заставить вещи происходить немедленно, в случае макета, который будет парой /invalidate()validate(), Бинго, желтый значок, даже когда на юге.[4] неприятный подкласс, который планирует настройку свойства значка (примечание: в его контракте нет ничего такого, что мешало бы подклассам делать это!). Поскольку собственность недаже не установлен, желтый необратно к квадрату [0]

В конце дня (но перед сном EDT :-), просто нет возможностидостоверно прогнозировать визуальный результатв течение сон. И визуальные эффекты - это только верхушка льда ...

/**
 * Unpredictable behaviour when sleeping the EDT.
 * http://stackoverflow.com/q/15600203/203657
 * 
 * [0] run as-is: property set but yellow not showing
 * [1] uncomment paintImmediately: yellow showing in center
 * [2] add label to south: yellow not showing
 * [3] force immediate in-/validation: yellow showing in south
 * [4] subclass label with invoked property setting: 
 *       property not set, yellow not showing
 * 
 */
public class ThreadSleeping {
    JFrame frame = new JFrame();
    JPanel panel = new JPanel();
    JButton button = new JButton("Load");
    JLabel label = new JLabel() {
// [4] subclass implemented to schedule the property setting         
//        @Override
//        public void setIcon(final Icon icon) {
//            SwingUtilities.invokeLater(new Runnable() {
//                public void run() {
//                    superSetIcon(icon);
//                    
//                }
//            });
//        }
//        
//        protected void superSetIcon(Icon icon) {
//            super.setIcon(icon);
//        }
//        
    };

    public ThreadSleeping() {
        panel.add(button);

        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent arg0) {
                Icon firstIcon = new FixedIcon(Color.YELLOW, 100, 100);
                Icon secondIcon = new FixedIcon(Color.RED, 500, 500);
                label.setIcon(firstIcon);
                // check if the property is already set
                System.out.println(label.getIcon());
                // following lines try to force the output before going to sleep
                // [3] paintImmediately + force immediate re-layout 
                //  label.invalidate();
                //  label.getParent().validate();
                // {1] paintImmediately (fine for center, no effect for south)
                // ((JComponent) label.getParent()).paintImmediately(0, 0, 5000, 5000);
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                label.setIcon(secondIcon);

            }
        });

        frame.add(panel, BorderLayout.NORTH);
        // un/comment one of the following, placing the
        // label either in CENTER (= sized to fill)
        frame.add(label, BorderLayout.CENTER);
        // [2] or in SOUTH (= sized to pref)
        // frame.add(label, BorderLayout.SOUTH);
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setSize(1024, 768);
        frame.setVisible(true);
    }

    /**
     * Simple fixed size Icon filling its area.
     */
    public static class FixedIcon implements Icon {

        private Color background;
        private int width;
        private int height;

        public FixedIcon(Color background, int width, int height) {
            this.background = background;
            this.width = width;
            this.height = height;
        }
        @Override
        public void paintIcon(Component c, Graphics g, int x, int y) {
            g.setColor(background);
            g.fillRect(0, 0, width, height);
        }

        @Override
        public int getIconWidth() {
            return width;
        }

        @Override
        public int getIconHeight() {
            return height;
        }
        @Override
        public String toString() {
            return "[" + background + " w/h " + width + "/" + height + "]";
        }


    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ThreadSleeping();
            }
        });
    }
}
@ brano88 - точно :-) kleopatra
Спасибо за ответ, мне это очень помогло. Итак, вывод: в подобных случаях мы всегда должны придерживаться таймера свинга или свингера, чтобы избежать зависания графического интерфейса, верно? Branislav Lazic

Похожие вопросы