在线程中使用画布对象做简单的动画 - Java [英] Using a canvas object in a thread to do simple animations - Java

查看:20
本文介绍了在线程中使用画布对象做简单的动画 - Java的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个小程序,就像现在写的那样,应该在按下运行"按钮后在顶部(代码中的drawingpanel)绘制和弹跳一个球.查看其他在线示例并使用来自未使用 Canvas 的其他程序的代码,我无法弄清楚为什么我的 Ball 对象没有显示.我已经测试了程序的流程,并且所有的方法都按照它们应该的方式被调用,所以代码没有进入 paint 方法的情况并非如此.任何关于使用 Canvas/Thread 的好资源都会很棒,或者对以下小程序的任何建议都会非常有用.谢谢!

I have an applet that, as written now, should be drawing and bouncing a ball around the top (drawingpanel in the code) after the "Run" button is pressed. Looking at other examples online and using code from a different program that did not use Canvas I am not able to figure out why my Ball object is not showing up. I have tested the flow of the program, and all the methods are being called as they should be, so it isn't the case where the code doesn't make it to the paint method. Any good resources on using Canvas/Thread would be great, or any advice on the following applet would be much appriciated. Thank you!

import java.awt.*;
import java.applet.*;
import java.awt.event.*;

public class Bounce2 extends Applet implements ActionListener, AdjustmentListener, Runnable
{
    private final static long serialVersionUID = 1L;

    //runtime variables
    boolean running = false;
    boolean currentlyCircle = true;
    boolean showtails = false;
    boolean kill = false;

    //buttons
    Button runbutton = new Button("Run"); 
    Button pausebutton = new Button("Pause");
    Button quitbutton = new Button("Quit");

    //text
    Label speedlabel = new Label("Speed");
    Label sizelabel = new Label("Size");

    //scrollbars
    private final int barHeight = 20;
    private final int SLIDER_WIDTH = 10;
    private final int MAXSPEED = 110;
    private final int MINSPEED = 0;
    private final int MAX_SIZE = 110;
    private final int MIN_SIZE = 10;
    Scrollbar speedbar = new Scrollbar(Scrollbar.HORIZONTAL, MAXSPEED/2, SLIDER_WIDTH, MINSPEED, MAXSPEED);
    Scrollbar sizebar = new Scrollbar(Scrollbar.HORIZONTAL, MAX_SIZE/2, SLIDER_WIDTH, MIN_SIZE, MAX_SIZE);

    //drawn objs
    Ball ball;
    Image buffer;
    int size = 50;  
    private Graphics obj;
    Point currentlocation = new Point(100,100);
    Point previouslocation;
    Point nextlocation;

    Rectangle circle;
    Rectangle screen;
    private Thread ballThread;

    //boundaries
    int bound_x;
    int bound_y;

    //directions
    int dx = 1; //1 = left, -1 = right
    int dy = 1; //1 = up, -1 = down

    //speed
    int speed = speedbar.getValue();
    int delay;

    //initialize the applet and draw everything
    public void init()
    {
        double colWeight[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};//15 cols
        double rowWeight[] = {1,1,1,1,1,1,1,1,1,1}; //10 rows
        int colWidth[] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};//15 cols
        int rowHeight[] = {1,1,1,1,1,1,1,1,1,1}; //10 rows
        GridBagConstraints c = new GridBagConstraints();
        GridBagLayout gbl = new GridBagLayout();
        gbl.rowHeights = rowHeight;
        gbl.rowWeights = rowWeight;
        gbl.columnWeights = colWeight;
        gbl.columnWidths = colWidth;
        c.anchor = GridBagConstraints.CENTER;

        setBounds(0,0,480,640);
        setLayout(new BorderLayout());
        Panel controlpanel = new Panel();
        controlpanel.setLayout(gbl);
        controlpanel.setSize(640,80);

        Panel drawingpanel = new Panel(null);
        drawingpanel.setSize(640,400);
        ball = new Ball();
        drawingpanel.add("Center", ball);
        Rectangle circle = new Rectangle(size, size);
        Rectangle screen = new Rectangle(0,0,640,400);
        drawingpanel.setVisible(true);

        //speed scrollbar
        c.weightx = 1;
        c.weighty = 1;
        c.gridwidth = 3;
        c.gridheight = 1;
        c.gridx = 1;
        c.gridy = 7;
        c.fill= GridBagConstraints.HORIZONTAL;
        gbl.setConstraints(this.speedbar,c);

        //run button
        c.weightx = 1;
        c.weighty = 1;
        c.gridwidth = 2;
        c.gridheight = 1;
        c.gridx = 5;
        c.gridy = 7;
        c.fill= GridBagConstraints.HORIZONTAL;
        gbl.setConstraints(this.runbutton,c);

        //pause button
        c.weightx = 1;
        c.weighty = 1;
        c.gridwidth = 2;
        c.gridheight = 1;
        c.gridx = 8;
        c.gridy = 7;
        c.fill= GridBagConstraints.HORIZONTAL;
        gbl.setConstraints(this.pausebutton,c);

        //size scrollbar
        c.weightx = 1;
        c.weighty = 1;
        c.gridwidth = 3;
        c.gridheight = 1;
        c.gridx = 11;
        c.gridy = 7;
        c.fill= GridBagConstraints.HORIZONTAL;
        gbl.setConstraints(this.sizebar,c);

        //speed text label
        c.weightx = 1;
        c.weighty = 1;
        c.gridwidth = 3;
        c.gridheight = 1;
        c.gridx = 1;
        c.gridy = 8;
        c.fill= GridBagConstraints.HORIZONTAL;
        gbl.setConstraints(this.speedlabel,c);

        //size text label
        c.weightx = 1;
        c.weighty = 1;
        c.gridwidth = 3;
        c.gridheight = 1;
        c.gridx = 11;
        c.gridy = 8;
        c.fill= GridBagConstraints.HORIZONTAL;
        gbl.setConstraints(this.sizelabel,c);

        //quit button
        c.weightx = 1;
        c.weighty = 1;
        c.gridwidth = 3;
        c.gridheight = 1;
        c.gridx = 6;
        c.gridy = 9;
        c.fill= GridBagConstraints.HORIZONTAL;
        gbl.setConstraints(this.quitbutton,c);

        //add to the screen
        controlpanel.add(this.speedbar);
        controlpanel.add(this.runbutton);
        controlpanel.add(this.pausebutton);
        controlpanel.add(this.sizebar);
        controlpanel.add(this.speedlabel);
        controlpanel.add(this.sizelabel);
        controlpanel.add(this.quitbutton);

        //add listners
        speedbar.addAdjustmentListener(this);
        runbutton.addActionListener(this);
        pausebutton.addActionListener(this);
        sizebar.addAdjustmentListener(this);
        quitbutton.addActionListener(this);

        //add the panels
        add("South", controlpanel);
        add("Center", drawingpanel);

        //drawing paramaters, draw the first object
        System.err.println(obj);
        obj = drawingpanel.getGraphics();
        nextlocation = new Point(currentlocation.x+dx, currentlocation.y+dy);

        setVisible(true);
        validate();
    }

    public void start()
    {
        if (ballThread == null)
        {
            ballThread = new Thread(this);
            ballThread.start();
            repaint();
        }
    }

        public void run()
{
    Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
    while (!kill)
    {
        if (running)
        {
            ball.move();
            repaint();
        }
        try
        {
            Thread.sleep(delay);
        }
        catch(InterruptedException e){System.err.println("Interrupted.");}
    }
    stop();
}

public void update(Graphics g)
{   
    Graphics buffer;
    Image offscreen = null;

    offscreen = createImage(bound_x, bound_y);
    buffer = offscreen.getGraphics();
    buffer.setColor(getBackground());
    buffer.fillRect(0,0,bound_x, bound_y);
    //update

    previouslocation = new Point(currentlocation);
    currentlocation = nextlocation;

    //draw
    buffer.setColor(Color.black);
    buffer.drawOval(nextlocation.x, nextlocation.y, size, size);
    buffer.fillOval(nextlocation.x, nextlocation.y, size, size);

    //draw rectangles out of vector     
    g.drawImage(offscreen, 0,0, null);
    paint(buffer);
}   

//class to handle animations
class Ball extends Canvas 
{
    public void move()
    {
        nextlocation = new Point(currentlocation.x+dx, currentlocation.y+dy);
        //if it will hit the right or left, flip the x direction and set it 
        if (nextlocation.x+size >= bound_x || nextlocation.x <= 0)
        { dx *= -1; }
        nextlocation.x += dx;
        //if it will hit the top or bottom, flip the y direction and set it
        if (nextlocation.y+size >= bound_y + 100 || nextlocation.y <= 0)
        { dy *= -1; }
        nextlocation.y += dy;
        setBounds(dx,dy,size,size);
        System.out.println(dx + "," + dy);
    }   

    public void paint(Graphics g)
    {
        super.paint(g);
        g.setColor(Color.black);
        g.drawOval(0, 0, size, size);
    }
}

    public void actionPerformed(ActionEvent e)
    {
        Object source = e.getSource();
        if (source == this.runbutton)
        {
            running = true;
        }
        else if (source == this.pausebutton)
        {
            running = false;
        }
        else if (source == this.quitbutton)
        {
            //kill processes
            kill = true;
            //remove listeners
            stop();
        }
    }

    public void adjustmentValueChanged(AdjustmentEvent e)
    {
        Object source = e.getSource();
        //set the new size. 
        if (source == sizebar)
        {
            //check for clipping
            int newsize = sizebar.getValue();

            // x
            if (currentlocation.x+newsize >= bound_x)
            { 
                newsize = bound_x - currentlocation.x - 1;
                sizebar.setValue(newsize);
            }

            // y
            if (currentlocation.y+newsize >= bound_y + 100)
            {
                newsize = bound_y+100 - currentlocation.y - 1;
                sizebar.setValue(newsize);
            }
            size = newsize;
        }
        if (source == speedbar)
        {
            speed = speedbar.getValue();
            delay = MAXSPEED - speedbar.getValue();
        }
    }

    public void stop()
    {
        this.speedbar.removeAdjustmentListener(this);
        this.runbutton.removeActionListener(this);
        this.pausebutton.removeActionListener(this);
        this.sizebar.removeAdjustmentListener(this);
        this.quitbutton.removeActionListener(this);
        Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
    }
}

推荐答案

老实说,我不知道从哪里开始.

To be honest, I don't know where to start with this one.

这是个坏主意.

private Graphics obj;
.
.
.
obj = drawingpanel.getGraphics();

任何组件图形都只是一个快照.在下一次重绘时,它将失效(我实际上是一个不同的对象)

Any components graphics is just a snap shot in time. On the next repaint, it will invalidated (and my actually be a different object)

你的绘画方法是错误的.以任何方式这样做实际上都是错误的地方,但是有很多事情是错误的.除了你应该很少覆盖顶级容器 paint 方法

You paint method is wrong. It's actually the wrong place to do this any way, but there are just to many things wrong. Apart from the fact you should very rarely override top level containers paint methods

public void paint(Graphics obj)
{
    // I can see you're trying to double buffer the graphics, but I would have a
    // buffer already set up...
    buffer = createImage(640,400);
    // You should NEVER dispose of Graphics context you didn't created...
    if (obj != null)
        obj.dispose();

    // Now we're really stuffed.  You've just overridden the screen graphics context
    obj = buffer.getGraphics();
    obj.setColor(getBackground());
    //update
    previouslocation = new Point(currentlocation);
    currentlocation = nextlocation;

    //draw
    obj.fillRect(currentlocation.x, currentlocation.y, size, size);
    obj.setColor(Color.black);
    obj.drawOval(nextlocation.x, nextlocation.y, size, size);
    obj.fillOval(nextlocation.x, nextlocation.y, size, size);
    /*
     *draw rectangles out of vector
     */
    // Now you drawing the buffer onto itself...???
    obj.drawImage(buffer, 0,0, null);
}   

回顾您的代码,我发现您正在向主绘制区域添加一个 Ball 组件,并且您正在为该绘制区域使用 null 布局.

Going back through you code, I found that you are adding a Ball component to you main paint area and you're using a null layout for this paint area.

如果丢弃布局管理器,则需要接管子组件的布局控制...

If you discard the layout manager, you need to take over control of laying out the child components...

您需要绘制 Ball...所以在您的 Ball 类中,您需要覆盖 paint 方法...

You need away to draw the Ball...so in your Ball class, you need to override the paint method...

public void paint(Graphics g) {
    super.paint(g);
    g.setColor(Color.black);
    g.drawOval(0, 0, size, size);
}

在您的 Ball#move 方法中,您需要更新球的位置...

In your Ball#move method, you need to update the location of the ball...

public void move() {
    // You've previous move code
    setBounds(dx, dy, size, size);
}

这会让你的绘画工作......或多或少......

That will get you painting working...more or less...

不过,我建议您放弃 AWT 并改用 Swing 组件,如果没有其他原因,它们是双缓冲的.

I would, however, suggest you discard AWT and use Swing components instead, if for no other reason, they're double buffered.

你看一看

你也可以看看

一些例子;)

这篇关于在线程中使用画布对象做简单的动画 - Java的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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