实验说明:实现模拟一个鸟笼,里面有20个鸟在其中自由移动(每个鸟是一个Thread类的子类,用一张图片表示鸟;笼子为Frame类子类),有三个按钮(start,stop,quit)操控笼子中鸟的行为,分别对应开始,暂停和退出程序
//Bird类
package CageAndBirds;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Toolkit;
public class Bird extends Thread{
private int xc = 2*(1 - 2*(int)Math.round(Math.random()));
//Math.random给予随机数(0.0~1.0),Math.round将随机数化为整数(0~1),然后利用强制类型转换化为INT
private int yc = 2*(1 - 2*(int)Math.round(Math.random()));
//鸟的坐标变化
private boolean running = false;
private Cage cage = null;
protected int x,y;//表示鸟此时位置
Image bird = Toolkit.getDefaultToolkit().getImage("pg.jpg");
public Bird(Cage _cage,int _x, int _y) {
cage = _cage;
x = _x;
y = _y;
start();
}
public void start() {
running = true;
super.start(); //将running的值修改后,再进行原来的资源分配操作(原资源分配操作可以在父类的start方法中可见)
}
public void halt() {
running = false;
}//停止运动
public void run() {
while(running) {//如果running的值为真就继续执行线程
move();
try {
sleep(120);
} catch (InterruptedException e) {
System.err.println("Thread Interrupted");
}
cage.repaint(); //每次循环执行完毕都刷新地图
}
}
private void move() {
x += xc;
y += yc;
if(x > cage.getSize().width ) {
x = cage.getSize().width; // 设置边界值
xc *= -1; // 调换方向
}
if(x < 0) {
x = 0;
xc *= -1;
}
if(y > cage.getSize().height) {
y = cage.getSize().height;
yc *= -1;
}
if(y < 0){
y = 0;
yc *= -1;
}
}
public void draw(Graphics g) {
g.drawImage (bird,x,y,30,40,cage);
}//将鸟的形象画在画布上
}
//Cage类
package CageAndBirds;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
public class Cage extends Frame implements ActionListener{
private Button quit =new Button("quit");
private Button start =new Button("start");
private Button stop =new Button("stop");
private Bird birds[] =new Bird[20]; //用数组存储在笼子中的鸟
Image bird = Toolkit.getDefaultToolkit().getImage("pg.jpg");
private class WindowCloser extends WindowAdapter{
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}
//构造笼子
public Cage() {
super("Cage With Birds");
setLayout(new FlowLayout());
add(quit);quit.addActionListener(this);
add(start);start.addActionListener(this);
add(stop);stop.addActionListener(this);
validate();setSize(1000, 1000);
setVisible(true);
addWindowListener(new WindowCloser());
for(int i=0; i<birds.length; i++) {
int x= (int)(getSize().width*Math.random());//将总的宽度乘以0~1之间的随机数得到随机宽度
int y= (int)(getSize().height*Math.random());
birds[i] = new Bird(this, x, y);//初始化数组中的每一只鸟
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (e.getSource() == stop) {
for(int i = 0; i<birds.length; i++) {
birds[i].halt();//停止每一只鸟的运动
}
}
if(e.getSource() == quit) {
System.exit(0);
}
if(e.getSource() == start) {
for(int i = 0; i<birds.length; i++) {
birds[i].halt();
birds[i] = new Bird(this, birds[i].x, birds[i].y);//每次再次开始时,会保证所有鸟是停止状态,然后重新初始化一组新的鸟对象
}
}
}
public void paint(Graphics g) {
for(int i =0; i<birds.length; i++) {
if(birds[i]!=null) {
birds[i].draw(g);
}
}
}//传递一个图像对象到鸟的draw方法中,让鸟自己在笼子中画出来
public static void main(String args[]) {
Cage table = new Cage();
}
}
实验结果展示:
实验总结:
(1)此实验涉及到一个编程技巧,实现线程随时终止运行->增加一个bool变量running来控制run函数的运行,同时这个running可以在我们新定义的函数halt中进行修改。
(2)注意多线程程序的编写,我们定义的每一只bird都是一个线程,线程的几种状态如下:新建(Newborn)、就绪(Runnable)、阻塞(Blocked)、运行(Running)和死亡(Dead)。一个新的线程,通过start方法进入就绪等待序列,CPU资源充足则会直接执行run方法。
(3)注意paint方法和repaint方法的联合使用,一般来说,paint方法中定义具体paint的内容,然后再需要刷新的地方调用repaint方法(repaint会自动调用paint方法,paint不需要单独显式调用)
网友评论