4

多くのボタンを備えたパネルを持つクラス (Class_GUI と呼ばれる) があります。Class_GUI には、ボタンのテキストと色を変更するいくつかのメソッドがあります。

actionPerformed メソッドを使用したプログラムもあります。これが呼び出されると、Class_GUI のインスタンスが作成され、Class_GUI メソッドが繰り返し呼び出され、ボタンなどが変更されます。

私が抱えている問題は、各 Class_GUI メソッドが呼び出された後にボタンを変更したいのに対し、 actionPerformed メソッドが完全に終了した後にのみボタンが正しく表示されることです。

これまでの私の試みは、各 Class_GUI メソッドで、メソッドの最後でこれを行います。

SwingUtilities.invokeLater(Refresh_GUI);

Refresh_GUI が定義されている場所:

Runnable Refresh_GUI = new Runnable(){
    public void run(){
        frame.revalidate();
        frame.repaint();
    }
};
4

4 に答える 4

3

メソッドがイベントディスパッチスレッドのコンテキスト内で呼び出されていると仮定すると、メソッドが競合actionPerformedするまでUIの更新は発生しません。メソッドが終了するまで、EDTはそれを変更できないため、使用しても変更されません。 (とりわけ)再描画要求の処理を続行します。actionPerformedSwingUtilities#invokeLateractionPerformed

最善の方法は、2番目のスレッドを開始し、そのスレッド内からUIコンポーネントを更新することです...ただし、SwingUtilities#invokeLaterEDT外のUIコンポーネントは絶対に更新しないため、使用を強制されます。

ただし、利点は、EDTが再描画要求の処理を開始するためにスレッドが競合する必要がないことです。

例で更新

public class SwingThreadUpdate {

    public static void main(String[] args) {
        new SwingThreadUpdate();
    }

    public SwingThreadUpdate() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new BlinkPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class BlinkPane extends JPanel {

        private JLabel label;
        private JButton button;

        public BlinkPane() {
            setLayout(new GridBagLayout());
            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridy = 0;

            label = new JLabel("Blinky");
            label.setBackground(Color.RED);
            button = new JButton("Click me");

            add(label, gbc);
            gbc.gridy++;
            add(button, gbc);

            button.addActionListener(new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    button.setEnabled(false);
                    new Thread(new BlinkTask(BlinkPane.this)).start();
                }
            });

        }

        private void setBlink(boolean blink) {
            label.setOpaque(blink);
        }

        private void reset() {
            button.setEnabled(true);
            label.setOpaque(false);
        }
    }

    public class BlinkTask implements Runnable {

        private BlinkPane blinkPane;

        protected BlinkTask(BlinkPane blinkPane) {
            this.blinkPane = blinkPane;
        }

        @Override
        public void run() {
            Blink blinkOn = new Blink(blinkPane, true);
            Blink blinkOff = new Blink(blinkPane, false);

            for (int index = 0; index < 10; index++) {
                if (index % 2 == 0) {
                    SwingUtilities.invokeLater(blinkOn);
                } else {
                    SwingUtilities.invokeLater(blinkOff);
                }
                try {
                    Thread.sleep(125);
                } catch (InterruptedException ex) {
                }
            }

            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    blinkPane.reset();
                }
            });

        }
    }

    public class Blink implements Runnable {

        private BlinkPane blinkPane;
        private boolean blink;

        public Blink(BlinkPane blinkPane, boolean blink) {
            this.blinkPane = blinkPane;
            this.blink = blink;
        }

        @Override
        public void run() {
            blinkPane.setBlink(blink);
            blinkPane.repaint();
        }
    }
}

詳細については、AWTおよびSwingでのPaintingを一読してください。

于 2012-12-06T19:16:18.437 に答える
2

actionPerform メソッドがコードを呼び出して for ループでボタンを更新する場合、invokeLater に更新コードを追加して、更新コードと描画コードの両方が 1 つずつ実行されるようにすることもできます。Invoke later は、現在のメソッドの実行が完了した後にのみ実行されるため、ペイントを確実に高速化する唯一の方法は、タスクを小さなピースに分割することです。

于 2012-12-06T19:07:30.743 に答える
1

まず、イベント ディスパッチ スレッドから (invokeLater を介して、または GUI イベント処理の一部として) GUI コンポーネントにのみアクセスしていることを確認します。

第 2 に、GUI コンポーネントのプロパティを変更すると、それ自体を再描画するイベントが自動的に送信されます。そうでない場合は、呼び出してみてくださいcomponent.repaint()。ただし、コンポーネント プロパティの変更が EDT で発生することが重要です。

于 2012-12-06T19:07:05.843 に答える
0

簡単な解決策は、ActionPerformed イベントの少ないタスク全体を実行して、イベント キューの最後にある画面を消去することです。したがって、最初に cleanScreen() 関数を実行します。これは、残りのイベントがすべてのイベントの終了を待機するためです。

    AnyButton.addActionListener(new ActionListener() {
        public void actionPerformed(ActionEvent e) {
            cleanScreen();        //Modify components before action performer event
            EventQueue.invokeLater( new Runnable() {
                @Override public void run() {
                    anytask();    //Action performer event
                }
            });                     
        }
    });
于 2014-02-05T00:22:46.477 に答える