在线程中使用画布对象做简单的动画 - Java [英] Using a canvas object in a thread to do simple animations - 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屋!