创建使用JApplet的动画 [英] Creating an animation using JApplet

查看:204
本文介绍了创建使用JApplet的动画的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的工作,它使用JApplet的,这使得球反弹向上和向下的Java程序。我能够绘制形状拖到JApplet的,一切都这样。我似乎无法得到它的移动。我已经看过这个,看到我需要创建一个暂停的形状,然后从JApplet的清除它,改变坐标,然后重新绘制形状,在新区域,但由于某种原因,它只是不是为我工作的方法。

感谢您预先的帮助。

 进口java.awt.Color中;
进口java.awt.Graphics;
进口javax.swing.JApplet中;
公共类圆扩展JApplet的{INT X = 100;
INT Y = 100;
INT直径= 50;
公共无效漆(图形G){INT xResize = 500;
INT yResize = 500;super.paint(G);
调整(xResize,yResize);
g.drawOval(X,Y,内径,外径);
}公共圆(INT运行startx,诠释startY,诠释startDiameter){this.x = startx的;
this.y = startY;
this.diameter = startDiameter;}公众诠释的getX(){
返回X;
}
公共无效setX的(INT运行startx){
X = startx的;
}
公众诠释的getY(){
返回是;
}
公共无效塞蒂(INT startY){
Y = startY;
}
公众诠释getDiameter(){
返回内径;
}
公共无效setDiameter(INT startDiameter){
直径= startDiameter;
}而(ball.getY()+ ballDiameter< WINDOWHEIGHT){g.clearRect(X-1,100,20,20);g.fillOval(X,100,20,20);尝试{视频下载(70);}赶上(例外五){}
pause.wait(0.05);//g.clearRect(0,0,windowWidth,windowHeight);g.clearRect(X-1,100,20,20);g.fillOval(X,100,20,20);尝试{视频下载(70);}赶上(例外五){}ball.setY(ball.getY()+间隔件);
}
而(ball.getY()+ ballDiameter大于0){g.clearRect(X-1,100,20,20);g.fillOval(X,100,20,20);尝试{视频下载(70);}赶上(例外五){}pause.wait(0.05);
//g.clearRect(0,0,WINDOWWIDTH,WINDOWHEIGHT);
ball.setY(ball.getY() - 间隔物);
}

弹跳球类:

 进口java.awt.Color中;
进口java.awt.Graphics;
进口javax.swing.JApplet中;公共类BouncingBall扩展JApplet的{公共无效漆(图形G){super.paint(G);最终诠释X = 0;
INT Y = 0;
最终诠释直径= 15;
最终诠释间隔= 5;
INT WINDOWWIDTH =的getWidth();
INT WINDOWHEIGHT =的getHeight();圈球=新圈(X,Y,直径);
暂停暂停=新的暂停();
INT ballDiameter = ball.getDiameter();
INT屋顶=的getHeight();


解决方案

首先,动画是随着时间变化的错觉。因此,首先,你需要一些方法来定期基地更新值。

其次,Swing是一个单线程的框架,这意味着任何阻止该线程将停止从事件过程中新的事件调度线程,包括重绘请求。

第三,预计所有交互,更改或更新的UI要从EDT的上下文中执行。

这意味着,你需要某种方式在后台等待(关EDT),它可以通知您,当它的时间来执行更新并同步的回那些更新到EDT。

javax.swing.Timer中的是用于此目的的最佳人选。它可以在后台为指定的一段时间等待;该时间段到期,便通知的ActionListener 的EDT的范围内,它可以重复。

通过覆盖的init 启动停止的方法 JApplet的

  @覆盖
公共无效的init(){
    super.init();
    定时器=新定时器(40,新的ActionListener(){        @覆盖
        公共无效的actionPerformed(ActionEvent的五){
        }
    });
}@覆盖
公共无效的start(){
    super.start();
    timer.start();
}@覆盖
公共无效停止(){
    timer.stop();
    super.stop();
}

基本上,这构建了一个定时,启动和适当地停止。

接下来,我们需要提供一些逻辑的动画...

正如我前面所说,动画运动在时间上的错觉。我们有一部分时间照顾(或多或少),现在我们需要的运动。

的基本思想是对变化的少量应用到当前值,并提供边界检查并最终重新绘制的结果。

  X + =增量;
如果(X℃,){
    X = 0;
    增量* = -1;
}否则如果(X +直径GT;的getWidth()){
    X =的getWidth() - 直径
    增量* = -1;
}
重绘();

在这里,我已经声明三角洲作为applet中实例变量,并设置它的值 2 。这个逻辑应该被添加到的actionPerformed 的方法的ActionListener 注册定时器

要获得此运行,你将需要删除您的构造函数,如小程序应该必须有一个默认/空构造。

您也应该删除调整油漆方法调用,因为这仅仅是将造成更多的重绘要发出请求,这最终会消耗你的CPU。

当你运行它,你可能会得到幸运,看到了一圈,偶尔(否则会闪烁)。这是因为在Swing顶层容器不是双缓冲。现在,你可以实现自己的缓冲策略,但Swing组件是双默认...

缓冲

要解决这个问题,我们可以创建一个简单的 DrawPanel ,从的JP​​anel 延伸和覆盖它的的paintComponent

所以,你可以用的东西最终会更喜欢...

 进口java.awt.BorderLayout中;
进口java.awt.Graphics;
进口java.awt.event.ActionEvent中;
进口java.awt.event.ActionListener;
进口javax.swing.JApplet中;
进口javax.swing.JPanel中;
进口javax.swing.Timer中;公共类圆扩展JApplet的{    私人INT三角洲= 2;    私人定时器定时器;
    私人DrawPane drawPane;    @覆盖
    公共无效的init(){
        super.init();
        的setLayout(新的BorderLayout());
        drawPane =新DrawPane();
        加(drawPane);
        定时器=新定时器(40,新的ActionListener(){            @覆盖
            公共无效的actionPerformed(ActionEvent的五){
                INT X = drawPane.getAnimationX();
                INT直径= drawPane.getDiameter();
                X + =增量;
                如果(X℃,){
                    X = 0;
                    增量* = -1;
                }否则如果(X +直径GT;的getWidth()){
                    X =的getWidth() - 直径
                    增量* = -1;
                }
                drawPane.setAnimationX(X);
                重绘();
            }
        });
    }    @覆盖
    公共无效的start(){
        super.start();
        timer.start();
    }    @覆盖
    公共无效停止(){
        timer.stop();
        super.stop();
    }    公共类DrawPane继承JPanel {        INT X = 100;
        INT Y = 100;
        INT直径= 50;        公共无效setAnimationX(INT X){
            this.x = X;
        }        公共无效setAnimationY(int y)对{
            this.y = Y;
        }        公众诠释getAnimationX(){
            返回X;
        }        公众诠释getAnimationY(){
            返回是;
        }        公众诠释getDiameter(){
            返回内径;
        }        公共无效setDiameter(INT startDiameter){
            直径= startDiameter;
        }        @覆盖
        保护无效paintComponent(图形G){
            super.paintComponent方法(G);
            g.drawOval(X,Y,内径,外径);
        }
    }
}

此外,覆盖方法时要小心,的getX 的getY 的方法有很特别的意义,你可能削弱您的应用程序通过overrding他们......

我也质疑是否有必要使用 JApplet的,倒不如简单地与使用的JFrame 这是显著更容易得到正常工作。

看看在Swing 并的并发= http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html相对=nofollow>如何使用Swing定时器了解更多详情

I am working on a Java program that uses a JApplet which makes a ball bounce up and down. I am able to paint the shape onto the JApplet and everything like that. I just can't seem to get it to move. I have looked into this and saw that I need to create a method that pauses the shape then clears it from the JApplet, changes coordinates, and then redraws the shape in the new area but for some reason it's just not working for me.

Thank you in advance for the help.

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


public class Circle extends JApplet {

int x=100;
int y=100;
int diameter=50;


public void paint(Graphics g) {

int xResize=500;
int yResize=500;

super.paint(g);
resize(xResize,yResize);
g.drawOval(x, y, diameter, diameter);   
}

public Circle (int startX, int startY,int startDiameter) {

this.x=startX;
this.y=startY;
this.diameter=startDiameter;

} 

public int getX() {
return x;
}
public void setX(int startX){
x=startX;
}
public int getY() {
return y;
}
public void setY(int startY){
y=startY;
}
public int getDiameter() {
return diameter;
}
public void setDiameter(int startDiameter){
diameter=startDiameter;


}

while (ball.getY() + ballDiameter < windowHeight) {

g.clearRect(x-1,100,20,20); 

g.fillOval(x,100,20,20); 

try 

{ 

Thread.sleep(70); 

} 

catch(Exception e) 

{ 

} 


pause.wait(0.05);

//g.clearRect(0,0,windowWidth,windowHeight);

g.clearRect(x-1,100,20,20); 

g.fillOval(x,100,20,20); 

try 

{ 

Thread.sleep(70); 

} 

catch(Exception e) 

{ 

} 

ball.setY( ball.getY()+spacer); 


}


while (ball.getY() + ballDiameter > 0) {

g.clearRect(x-1,100,20,20); 

g.fillOval(x,100,20,20); 

try 

{ 

Thread.sleep(70); 

} 

catch(Exception e) 

{ 

} 

pause.wait(0.05);
//g.clearRect(0,0, windowWidth, windowHeight);
ball.setY(ball.getY()-spacer);


}

Bouncing Ball Class:

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

public class BouncingBall extends JApplet {

public void paint(Graphics g) {

super.paint(g);

final int x = 0;
int y = 0;
final int diameter = 15;
final int spacer = 5;
int windowWidth = getWidth();
int windowHeight = getHeight();

Circle ball = new Circle(x, y, diameter);
Pause pause = new Pause();
int ballDiameter = ball.getDiameter();
int roof = getHeight();

解决方案

Firstly, animation is the illusion of change over time. So first, you need some way to update your values on a regular bases.

Secondly, Swing is a single threaded framework, this means that anything that blocks this thread will stop the Event Dispatching Thread from process new events, including repaint requests.

Thirdly, all interactions, changes or updates to the UI are expected to be executed from within the context of the EDT.

This means, you need some way to wait in the background (off the EDT), which can notify you when it's time to perform an update and have those updates synched back to the EDT.

javax.swing.Timer is a perfect candidate for this purpose. It can wait in the background for a specified period of time; It will notify the ActionListener within the context of the EDT when the time period expires and it can repeat.

Start by overriding the init, start and stop methods of the JApplet

@Override
public void init() {
    super.init(); 
    timer = new Timer(40, new ActionListener() {

        @Override
        public void actionPerformed(ActionEvent e) {
        }
    });
}

@Override
public void start() {
    super.start();
    timer.start();
}

@Override
public void stop() {
    timer.stop();
    super.stop(); 
}

Basically, this constructs a Timer, starts and stops it appropriately.

Next, we need to supply some logic for the animation...

As I said before, animation is the illusion of movement over time. We have the time part taken care of (more or less), now we need the movement.

The basic idea is to apply a small amount of change to the current value and provide boundary checking and finally repaint the result.

x += delta;
if (x < 0) {
    x = 0;
    delta *= -1;
} else if (x + diameter > getWidth()) {
    x = getWidth() - diameter;
    delta *= -1;
}
repaint();

Here, I've declared delta as instance variable within the applet and set it's value to 2. This logic should be added to the actionPerformed method of the ActionListener registered with the Timer

To get this to run, you will need to remove your constructor, as applets should must have a default/empty constructor.

You should also remove the resize call from the paint method, as this is just going to cause more repaint requests to be issued, which will eventually consume your CPU.

When you run it, you might get lucky and see the circle, occasionally (or it will flicker). This is because top level containers in Swing aren't double buffered. Now, you could implement your own buffering strategy, but Swing components are double buffered by default...

To fix this, we can create a simple DrawPanel that extends from a JPanel and override it's paintComponent method

So you could end up with something more like...

import java.awt.BorderLayout;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JApplet;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Circle extends JApplet {

    private int delta = 2;

    private Timer timer;
    private DrawPane drawPane;

    @Override
    public void init() {
        super.init();
        setLayout(new BorderLayout());
        drawPane = new DrawPane();
        add(drawPane);
        timer = new Timer(40, new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                int x = drawPane.getAnimationX();
                int diameter = drawPane.getDiameter();
                x += delta;
                if (x < 0) {
                    x = 0;
                    delta *= -1;
                } else if (x + diameter > getWidth()) {
                    x = getWidth()- diameter;
                    delta *= -1;
                }
                drawPane.setAnimationX(x);
                repaint();
            }
        });
    }

    @Override
    public void start() {
        super.start();
        timer.start();
    }

    @Override
    public void stop() {
        timer.stop();
        super.stop();
    }

    public class DrawPane extends JPanel {

        int x = 100;
        int y = 100;
        int diameter = 50;

        public void setAnimationX(int x) {
            this.x = x;
        }

        public void setAnimationY(int y) {
            this.y = y;
        }

        public int getAnimationX() {
            return x;
        }

        public int getAnimationY() {
            return y;
        }

        public int getDiameter() {
            return diameter;
        }

        public void setDiameter(int startDiameter) {
            diameter = startDiameter;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawOval(x, y, diameter, diameter);
        }
    }
}

Also, be careful when overriding methods, the getX and getY methods have very special meanings, you could cripple your application by overrding them...

I'd also question the need to use JApplet, it would be better to simply start with using a JFrame which is significantly easier to get working properly.

Take a look at Concurrency in Swing and How to use Swing Timers for more details

这篇关于创建使用JApplet的动画的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆