3

まず第一に、私はこのアプローチが間違っていることを知っていると言いたいので、純粋な好奇心のためにこの質問をしています。私がこのようなswingアプリケーションを持っているとしましょう:

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画像が表示され、GUIが2秒間フリーズし、その後、画像が表示されると思いKoala.jpgます。しかし、何が起こるかというと、ボタンをクリックすると、GUIが2秒間フリーズし、Koala.jpg表示されます。Tulips.jpgその前に。しかし、私を混乱させるのは、それらSystem.out.println("Tulips painted");とを置くときSystem.out.println("Koala painted");です。したがって、ボタンをクリックすると、「チューリップペイント」と印刷され、2秒後に「コアラペイント」と印刷されます。誰かがここで何が起こっているのか教えてもらえますか?よろしく。

4

2 に答える 2

3
  1. この場合、ouf Swing GUIをプログラムでフリーズしますが、 別のJComponentの更新がないため、機能します。

  2. Swing GUIに更新された別のスレッド、Thread.sleep(int)freeze Event Dispatch Threadがいくつかある場合は、機能しません。

  3. デフォルトでは、JComponents XxxModelsneverへのすべての更新はに表示されますJComponents view

  4. 例スリープが終了するまで、GUIに更新されたものはすべて失われます

于 2013-03-24T15:24:39.093 に答える
2

私がコメントで述べようとした点:

edtをスリープ状態にすると、結果として生じる不正な動作は基本的に予測できません。

何が起こるかわからないという意味で予測不可能。私たちにできることは、推測することだけです...

技術的な理由は、ほとんどのUIの更新はすぐには行われないが、スケジュールされているためです。背後の列で何が待機しているかを実際に知ることはできません。覚えておいてください:それはたった1つのレーンであり、actionPerformedにいるとき、そこに座っているのは私たちです。

教育上の理由から、以下のコードは、さまざまなシナリオを示すためにコメントを外す/コメントするための数行の元のコードです。

  • [0]寝る前/寝た後のアイコンのリセット:すでにお気づきのように、プロパティが取得されても最初のアイコンは表示されません。技術的な理由:視覚的な更新label.repaint()は、EDTで後の処理のためにスケジュールされたものを介して行われます(APIドキュメントに記載されています)
  • [1] api docをざっと見ると、別のメソッドに気づきます。paintImmediately(...)これは、その名前が示すとおりに実行するように文書化されており、EDTの場合と同様に、呼び出しが許可されています。成功したように見えます。黄色のアイコンが表示されます。
  • [2]しかし待ってください:境界線の中央にあるので、ラベルはアイコンがあるかどうかに関係なく、とにかくその領域を埋めます。南へのfiのように、再レイアウトが必要な領域に配置してみましょう。正方形[0]に戻り、黄色のアイコンが表示されません。
  • [3]のソースを調べるとsetIcon(..)、レイアウトが...再度スケジュールされていることがわかります。invalidate()正方形[1]で、ペア/になるレイアウトの場合、物事をすぐに発生させることができることを学びました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();
            }
        });
    }
}
于 2013-03-25T12:16:08.297 に答える