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

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

问题描述

我有一个小程序,就像现在写的,应该借鉴和周围的顶反弹球( drawingpanel 在code)中的运行后,按钮pssed $ p $。在其他的例子看网上,并使用code从不同的程序,没有用帆布我无法弄清楚,为什么我的球对象没有显示出来。我已经测试程序的流程,并且所有的方法都被调用,因为它们应该的,所以它不是的情况下code不使其向涂料方法。在使用Canvas /线程任何好的资源,将是巨大的,或者在下面的小应用程序的任何意见将大大appriciated。谢谢!

 进口java.awt中的*。
导入的java.applet。*;
java.awt.event中导入*。公共类Bounce2扩展的Applet实现的ActionListener,的AdjustmentListener,可运行
{
    私人最终静态长的serialVersionUID = 1L;    //运行时变量
    布尔运行= FALSE;
    布尔currentlyCircle = TRUE;
    布尔showtails = FALSE;
    布尔杀= FALSE;    //纽扣
    按钮runbutton =新按钮(运行);
    按钮暂停按钮=新按钮(暂停);
    按钮quitbutton =新按钮(退出);    //文本
    标签speedlabel =新标签(速度);
    标签sizelabel =新标签(大小);    //滚动条
    私人最终诠释barHeight = 20;
    私人最终诠释SLIDER_WIDTH = 10;
    私人最终诠释MAXSPEED = 110;
    私人最终诠释MINSPEED = 0;
    私人最终诠释MAX_SIZE = 110;
    私人最终诠释MIN_SIZE = 10;
    滚动条speedbar =新的滚动条(为Scrollbar.HORIZONTAL,MAXSPEED / 2,SLIDER_WIDTH,MINSPEED,MAXSPEED);
    滚动条sizebar =新的滚动条(为Scrollbar.HORIZONTAL,MAX_SIZE / 2,SLIDER_WIDTH,MIN_SIZE,MAX_SIZE);    //绘制的OBJ文件
    波波球;
    图像缓冲区;
    INT大小= 50;
    私有图形OBJ;
    点currentlocation =新点(100,100);
    点previouslocation;
    点nextlocation;    矩形圈;
    矩形屏;
    私人螺纹ballThread;    //边界
    INT bound_x;
    INT bound_y;    //方向
    INT DX = 1; // 1 =左侧,1 =右
    INT DY = 1; // 1 =起来,-1 =下跌    //速度
    INT速度= speedbar.getValue();
    INT延迟;    //初始化小程序和借鉴一切
    公共无效的init()
    {
        双colWeight [] = {1,1,1,1,1,1,1,1,1,1,1,1,1,1,1}; // 15 COLS
        双rowWeight [] = {1,1,1,1,1,1,1,1,1,1}; // 10行
        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行
        GridBagConstraints的C =新的GridBagConstraints();
        GridBagLayout的GBL =新的GridBagLayout();
        gbl.rowHeights = rowHeight的;
        gbl.rowWeights = rowWeight;
        gbl.columnWeights = colWeight;
        gbl.columnWidths =列表ColWidth;
        c.anchor = GridBagConstraints.CENTER;        的setBounds(0,0,480,640);
        的setLayout(新的BorderLayout());
        面板ControlPanel控制=新面板();
        controlpanel.setLayout(GBL);
        controlpanel.setSize(640,80);        面板drawingpanel =新面板(NULL);
        drawingpanel.setSize(640400);
        球=新球();
        drawingpanel.add(中心,球);
        矩形圈=新的Rectangle(尺寸,大小);
        矩形屏幕=新的Rectangle(0,0,640,400);
        drawingpanel.setVisible(真);        //滚动速度
        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);        //运行按钮
        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);        //暂停按钮
        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);        //滚动条大小
        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);        //速度文本标签
        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);        //大小文本标签
        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);        //退出按钮
        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);        //添加到屏幕
        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);        //添加listners
        speedbar.addAdjustmentListener(本);
        runbutton.addActionListener(本);
        pausebutton.addActionListener(本);
        sizebar.addAdjustmentListener(本);
        quitbutton.addActionListener(本);        //添加面板
        加(南方,ControlPanel控制);
        加(中心,drawingpanel);        //绘图PARAMATERS,绘制的第一个对象
        通信System.err.println(OBJ);
        物镜= drawingpanel.getGraphics();
        nextlocation =新的点(currentlocation.x + DX,currentlocation.y + DY);        调用setVisible(真);
        验证();
    }    公共无效的start()
    {
        如果(ballThread == NULL)
        {
            ballThread =新主题(本);
            ballThread.start();
            重绘();
        }
    }        公共无效的run()
{
    。Thread.currentThread()setPriority(Thread.MAX_PRIORITY);
    而(!杀)
    {
        如果(运行)
        {
            ball.move();
            重绘();
        }
        尝试
        {
            视频下载(延迟);
        }
        赶上(InterruptedException的E){通信System.err.println(中断);}
    }
    停止();
}公共无效更新(图形G)
{
    图形缓冲区;
    图像屏幕外= NULL;    屏幕外=的createImage(bound_x,bound_y);
    缓冲= offscreen.getGraphics();
    buffer.setColor(的getBackground());
    buffer.fillRect(0,0,bound_x,bound_y);
    //更新    previouslocation =新的点(currentlocation);
    currentlocation = nextlocation;    //画
    buffer.setColor(Color.black);
    buffer.drawOval(nextlocation.x,nextlocation.y,尺寸,大小);
    buffer.fillOval(nextlocation.x,nextlocation.y,尺寸,大小);    //绘制矩形出矢量
    g.drawImage(屏幕外,0,0,NULL);
    油漆(缓冲);
}//类来处理动画
Ball类扩展画布
{
    公共无效移动()
    {
        nextlocation =新的点(currentlocation.x + DX,currentlocation.y + DY);
        //如果它将击中右侧或左侧,翻转x方向,并将其设置
        如果(nextlocation.x +尺寸> = || bound_x&nextlocation.x LT; = 0)
        {DX * = -1; }
        nextlocation.x + = DX;
        //如果它将击中的顶部或底部,翻转y方向,并将其设置
        如果(nextlocation.y +尺寸> = bound_y + 100 || nextlocation.y< = 0)
        {DY * = -1; }
        nextlocation.y + =颐;
        的setBounds(DX,DY,尺寸,大小);
        的System.out.println(DX +,+ DY);
    }    公共无效漆(图形G)
    {
        super.paint(G);
        g.setColor(Color.black);
        g.drawOval(0,0,尺寸,大小);
    }
}    公共无效的actionPerformed(ActionEvent的五)
    {
        对象源= e.getSource();
        如果(来源== this.runbutton)
        {
            运行= TRUE;
        }
        否则,如果(来源== this.pausebutton)
        {
            运行= FALSE;
        }
        否则,如果(来源== this.quitbutton)
        {
            //终止进程
            杀= TRUE;
            //删除监听器
            停止();
        }
    }    公共无效adjustmentValueChanged(的AdjustmentEvent E)
    {
        对象源= e.getSource();
        //设置新的大小。
        如果(来源== sizebar)
        {
            //检查裁剪
            INT newsize = sizebar.getValue();            // X
            如果(currentlocation.x + newsize> = bound_x)
            {
                newsize = bound_x - currentlocation.x - 1;
                sizebar.setValue(newsize);
            }            //ÿ
            如果(currentlocation.y + newsize> = bound_y + 100)
            {
                newsize = bound_y + 100 - currentlocation.y - 1;
                sizebar.setValue(newsize);
            }
            大小= newsize;
        }
        如果(来源== speedbar)
        {
            速度= speedbar.getValue();
            延迟= MAXSPEED - speedbar.getValue();
        }
    }    公共无效停止()
    {
        this.speedbar.removeAdjustmentListener(本);
        this.runbutton.removeActionListener(本);
        this.pausebutton.removeActionListener(本);
        this.sizebar.removeAdjustmentListener(本);
        this.quitbutton.removeActionListener(本);
        。Thread.currentThread()setPriority(从Thread.MIN_PRIORITY);
    }
}


解决方案

说实话,我不知道在哪里与这一个开始。

这是一个坏主意。

 私有图形OBJ;



物镜= drawingpanel.getGraphics();

任何组件的图形仅仅是时间上的快照。在接下来的重绘,这将无效(和我实际上是一个不同的对象)

您画的方法是错误的。它实际上是错误的地方要做到这一点任何方式,但也有只是很多事情是错误的。除了事实上,你应该很少覆盖顶层容器油漆方法

 公共无效漆(图形OBJ)
{
    //我可以看到你想要双重缓冲的图形,但我有一个
    //缓冲已经建立......
    缓冲=的createImage(640400);
    //你永远不应该处理图形上下文的你没有创建...
    如果(OBJ!= NULL)
        obj.dispose();    //现在我们真的塞满。你刚刚覆盖屏幕图形上下文
    物镜= buffer.getGraphics();
    obj.setColor(的getBackground());
    //更新
    previouslocation =新的点(currentlocation);
    currentlocation = nextlocation;    //画
    obj.fillRect(currentlocation.x,currentlocation.y,尺寸,大小);
    obj.setColor(Color.black);
    obj.drawOval(nextlocation.x,nextlocation.y,尺寸,大小);
    obj.fillOval(nextlocation.x,nextlocation.y,尺寸,大小);
    / *
     *绘制矩形出矢量
     * /
    //现在你绘制缓冲到自身...?
    obj.drawImage(缓冲液,0,0,空);
}

让我们回到通过你code,我发现你要添加组件到你主漆面积,您使用的是布局这一油漆区。

如果你放弃了布局管理器,你需要接管布局子组件的控制...

您需要走绘制 ...所以在你的类,你需要重写油漆方法...

 公共无效漆(图形G){
    super.paint(G);
    g.setColor(Color.black);
    g.drawOval(0,0,尺寸,大小);
}

在你的球#移动方法,你需要更新球的位置...

 公共无效移动(){
    //你已经previous举动code
    的setBounds(DX,DY,尺寸,大小);
}

这将让你画工作...或多或少...

我会的,不过,建议你放弃AWT和使用Swing组件替代,如果没有其他原因,他们双缓冲。

您需要通过

一起来看看

您也可以看看

有关的一些例子;)

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.

This is a bad idea.

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)

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);
}   

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...

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);
}

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...

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

You take a look through

You could also have a look at

For some examples ;)

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

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