0

私は持っている:

  • JButton を含む JFrame。
  • アニメーションを表示する別の Canvas サブクラス。

そして、JButton を押すと、Canvas サブクラスをアニメーションとして表示する新しい JFrame を表示したいと考えています。

私が現在直面している問題は、新しい JFrame が表示されることですが、何もレンダリングする機会がなく、メイン フレームの JButton が押されたままです。この背後にあるロジックは、EDT が JButton をリリース済みとして表示するなどのジョブを完了していないため、アニメーション メソッドを実行する機会がなく、デッドロックに陥っているということです。

このロジックは、私が新しいスレッドを作成することでこの作業を行っていたため、以前はうまく機能していましたが、最近 Java、スレッド、および Swing について詳しく学んで、すべての Swing 関連のイベントを 1 つのスレッド (EDT) で処理する必要があることを知りました。 .

これは、以前にどのように機能させたかについて私を混乱させますが、invokeLaterを使用すると問題が解決すると信じています。JFrame を表示してアニメーションを表示するジョブはキューの最後に配置され、JButton の解放などを許可するためです。しかし、私は運がありませんでした。私は何かを完全に誤解していますか?

ありがとう!

(また、JPanel とは対照的に Canvas クラスの使用についてコメントしないでください。私には理由があります)。

サンプルコード:

Test5 (メイン メソッドを持つクラス)。

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*

public class Test5 {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
              public void run() {
                  new Test5().setup();
              }
            });
          }
    private void setup() {
        JFrame frame = new JFrame("Test");
        JButton button = new JButton("Click here");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                SwingUtilities.invokeLater(new Runnable() {
                    public void run() {
                        newFrame();
                    }
                  });
            }
        });
        frame.getContentPane().add(button);
        frame.pack();
        frame.setVisible(true);
        frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
    private void newFrame() {
        JFrame newFrame = new JFrame("The new frame");
        newFrame.setVisible(true);
        newFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        CanvasClass canvas = new CanvasClass();
        newFrame.getContentPane().add(canvas);
        newFrame.pack();
        canvas.runAnimation();
    }
}

CanvasClass (キャンバス サブクラス)

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;


public class CanvasClass extends Canvas {
    int x;
    public CanvasClass() {
        setSize(new Dimension(550,550));
        this.x = (int) (Math.random() * 255);
    }

    //@Override
    public void paint(Graphics g) {
        g.setColor(new Color(x, x, x));
        g.fillOval(0,0,500,500);
    }

    void runAnimation() {
        while (true) {
            randomise();
            repaint();
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    void randomise() {
    x = (int) (Math.random() * 255);
    }
}
4

1 に答える 1

3

実際には EDT で呼び出しますが、canvas.runAnimation();

実行するコードを別のThread場所(スリープを呼び出すことができる場所)に配置しますがrepaint()SwingUtilities.invokeLater()

または、 a を定義して Timer でjavax.swing.Timer呼び出す方がさらに良いrunAnimation()actionPerformed()

アップデート:

  int delay = 20; //milliseconds
  ActionListener taskPerformer = new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
          canvasInstance.randomise();
          canvasInstance.repaint();
      }
  };
  new Timer(delay, taskPerformer).start();

runAnimation() の代わりに呼び出される

于 2015-01-08T12:13:01.187 に答える