0

我有:

  • 一个带有 JButton 的 JFrame。
  • 一个单独的 Canvas 子类来显示动画。

我希望在按下 JButton 时调出一个新的 JFrame,显示 Canvas 子类的动画。

我现在面临的问题是新的 JFrame 出现了,但是它没有机会渲染任何东西,并且主框架上的 JButton 保持按下状态。我认为这背后的逻辑是 EDT 还没有完成它的工作,例如显示 JButton 已释放,因此没有机会运行动画方法并最终陷入死锁。

这个逻辑在过去对我很好,因为我通过创建一个新线程来完成这项工作,但是最近了解了更多关于 Java、线程和 Swing 的知识,我开始知道所有与 Swing 相关的事件都必须在一个线程上处理:EDT .

这让我对我之前如何让它工作感到困惑,但让我相信使用 invokeLater 会帮助解决问题;因为使 JFrame 可见并显示动画的工作将放置在队列的末尾,允许 JButton 释放等。但是我没有运气;我完全误解了什么吗?

谢谢!

(也请不要评论我使用 Canvas 类而不是 JPanel,我有我的理由)。

示例代码:

Test5(带有 main 方法的类)。

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地方(您可以在其中调用 sleep),但调用repaint()inSwingUtilities.invokeLater()

甚至更好地定义 ajavax.swing.TimerrunAnimation()在 Timer 中调用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 回答