为什么我的JFrame对象不像我期望的那样动画?

时间:2014-09-22 23:37:18

标签: java swing jpanel paintcomponent thread-sleep

我正在尝试根据Head First Java练习为一个圆圈制作动画。原始练习要求在“AnimatedBall”类中使用内部“MyDrawPanel”类,但我正在尝试执行外部MyDrawPanel类。我没有错误,但也没有动画。我假设它与我传递值到MyDrawPanel构造函数有关,当我运行for循环时不会更新,但我想知道为什么会这样。

AnimatedBall2.java:

import javax.swing.JFrame;

public class AnimatedBall2 {
    JFrame frame = new JFrame();
    int height = 300;
    int width = 300;
    int x = 70;
    int y = 70;


    public static void main(String[] args){
        AnimatedBall2 gui = new AnimatedBall2();
        gui.go();
    }

    public void go(){
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        MyDrawPanel panel = new MyDrawPanel(x, y, height, width);

        frame.getContentPane().add(panel);
        frame.setSize(height,width);
        frame.setVisible(true);

        for(int i = 0; i < 100; i++){
            x++;
            y++;
            panel.repaint();

            try{
                Thread.sleep(50);
            } catch(Exception ex){}
        }
    }   
}

MyDrawPanel.java:

import java.awt.Color;
import java.awt.Graphics;
import javax.swing.JPanel;


public class MyDrawPanel extends JPanel{
    int x;
    int y;
    int height;
    int width;

    public MyDrawPanel(int x1, int y1, int z1, int z2){
        x = x1;
        y = y1;
        height = z1;
        width = z2;

    }


    public void paintComponent(Graphics g){
        g.setColor(Color.white);
        g.fillRect(0, 0, height, width);
        g.setColor(Color.orange);
        g.fillOval(x, y, 100, 100); 

    }
}

2 个答案:

答案 0 :(得分:2)

Swing是一个单线程框架,也就是说,有一个线程负责处理系统中的所有事件并安排绘制。

任何阻止此线程的东西都会阻止它处理新事件或绘制请求。

这是一个非常糟糕的主意......

public void go(){
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    MyDrawPanel panel = new MyDrawPanel(x, y, height, width);

    frame.getContentPane().add(panel);
    frame.setSize(height,width);
    frame.setVisible(true);

    for(int i = 0; i < 100; i++){
        x++;
        y++;
        panel.repaint();

        try{
            Thread.sleep(50);
        } catch(Exception ex){}
    }
}   

添加可能会锁定您的应用程序......

查看Concurrency in Swing了解更多详情。您还应该查看Initial Threads

在这种情况下,我建议使用javax.swing.Timer,有关详细信息,请参阅How to use Swing Timers

主要问题是,您已在x课程中取消yAnimatedBall2 ...

public class AnimatedBall2 {
    //...
    int x = 70;
    int y = 70

在你的MyDrawPanel班级......

public class MyDrawPanel extends JPanel{
    int x;
    int y;

但是你的循环正在更新AnimatedBall2类中的值,这意味着MyDrawPanel中的值永远不会改变

您需要添加某种“更新”方法,该方法可以告诉MyDrawPanel它应该相应地更新x / y值...

这让我们看到... Swing不是线程安全的,所有修改或与UI的交互都应该在Event Dispatching Thread的上下文中完成...这就是为什么我建议使用Swing {{1因为它在EDT的上下文中触发它的通知。

执行自定义绘画时,您应该在执行自己的任何自定义绘画之前调用Timer。你也不应该转发“魔术”号码

super.paintComponent

布局管理器可以根据需要更改组件的大小,相反,您应该使用g.fillRect(0, 0, height, width); getWidth,它将准确地告诉您当前组件的大小是多少

例如......

getHeight

答案 1 :(得分:0)

for(int i = 0; i < 100; i++){
            x++;
            y++;
            panel.repaint();

            try{
                Thread.sleep(50);
            } catch(Exception ex){}
        }

x和y是int类型,而不是指针。所以当你做x ++和y ++时。它实际上没有更新你在构造函数中传入的x,y值