为什么我们要让MainFrame面板主类继承JFrame类:
答:我们需要重绘面板,需要重写面板类的paint()方法,我们让MainFrame类继承面板类它本身就成为了一个面板,就可以对其paint()方法进行重写。
package Threadanimation.copy310;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
/**
* 界面类
*
* @author lcz
*
*/
public class MainFrame extends JFrame { // 继承面板,因为之后要重写它的paint方法
private ArrayList<Rect> rectList; // 声明动态数组
private Graphics g; // 声明画笔对象
private RectMove rectmove; // 声明RectMove对象rectmove
private Random random;
/**
* 主函数
*
* @param args
*/
public static void main(String[] args) {
MainFrame frame = new MainFrame();
frame.initUI();
}
/**
* 初始化界面的方法
*/
public void initUI() {
this.setTitle("线程动画");
this.setSize(700, 600);
this.setLocationRelativeTo(null);
this.setDefaultCloseOperation(3);
this.setVisible(true);
g = this.getGraphics();
rectList = new ArrayList<Rect>();
random = new Random();
int size = random.nextInt(11) + 10; // 方块个数最少为十个
for (int i = 0; i < size; i++) { // 循环实例化Rect对象
Rect rect = new Rect();
rect.setRect(random.nextInt(this.getWidth()), random.nextInt(this.getHeight()), 100, 70, Color.BLACK,0);
rectList.add(rect); // 把Rect对象添加给动态数组
}
rectmove = new RectMove();
rectmove.setAttribute(this, rectList);
rectmove.start(); // 调用start()方法
}
public void paint(Graphics g) {
super.paint(g); // 调用父类paint()方法
for (int i = 0; i < rectList.size(); i++) {
Rect rect = rectList.get(i); // 取出数组中的Rect对象
rect.drawRect(g); // 调用drawRect方法
}
}
}
为什么要给方块类增加标志位flag?
答:我们想让方块在触碰到界面边缘时改变移动路径,我们可以采用给每个方块增加标志位的方式判断其碰撞界面边缘的次数,从而得到其移动方向,从而进行相应的移动。
注意:如何自动添加get和set方法。
package Threadanimation.copy310;
import java.awt.Color;
import java.awt.Graphics;
/**
* 形状类
*
* @author lcz
*
*/
public class Rect {
private int x, y, width, height;
private Color color;
private int flag; // 标志位,记录该方块撞到界面的次数
/*
* 传参方法,作用与构造方法相同
*/
public void setRect(int x, int y, int width, int height, Color color, int flag) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
this.color = color;
this.flag = flag;
}
/*
* 画图方法
*/
public void drawRect(Graphics g) {
g.setColor(color);
g.fillRect(x, y, width, height);
}
/**
* @return the x
*/
public int getX() {
return x;
}
/**
* @param x the x to set
*/
public void setX(int x) {
this.x = x;
}
/**
* @return the y
*/
public int getY() {
return y;
}
/**
* @param y the y to set
*/
public void setY(int y) {
this.y = y;
}
/**
* @return the width
*/
public int getWidth() {
return width;
}
/**
* @param width the width to set
*/
public void setWidth(int width) {
this.width = width;
}
/**
* @return the height
*/
public int getHeight() {
return height;
}
/**
* @param height the height to set
*/
public void setHeight(int height) {
this.height = height;
}
/**
* @return the color
*/
public Color getColor() {
return color;
}
/**
* @param color the color to set
*/
public void setColor(Color color) {
this.color = color;
}
/**
* @return the flag
*/
public int getFlag() {
return flag;
}
/**
* @param flag the flag to set
*/
public void setFlag(int flag) {
this.flag = flag;
}
}
我们为什么要在run方法中添加repaint()方法?
答:线程在运行过程中会不断的调用自己的run方法,我们在run方法中调用repaint()方法就会对界面不断的进行重绘,这与我们在run方法中不断改变x,y坐标的值是一个道理。
package Threadanimation.copy310;
import java.util.ArrayList;
import java.util.Random;
/**
* 线程类
*
* @author lcz
*
*/
public class RectMove extends Thread {
private ArrayList<Rect> rectList;
private MainFrame mainframe;
private Random random;
public void setAttribute(MainFrame mainframe, ArrayList rectList) {
this.mainframe = mainframe;
this.rectList = rectList;
}
@Override
public void run() {
while (true) {
for (int i = 0; i < rectList.size(); i++) { //取出数组中的元素
if (rectList.get(i).getFlag() % 2 == 0) { //判断方块移动方向,如果%2为0表示往右移动
int x = rectList.get(i).getX() + 10;
int y = rectList.get(i).getY();
rectList.get(i).setX(x);
rectList.get(i).setY(y);
if (rectList.get(i).getX() > 600) { //判断方块是否撞墙
int flag = rectList.get(i).getFlag() + 1;
rectList.get(i).setFlag(flag);
}
} else if (rectList.get(i).getFlag() % 2 != 0) {//判断方块移动方向
int x = rectList.get(i).getX() - 10;
int y = rectList.get(i).getY();
rectList.get(i).setX(x);
rectList.get(i).setY(y);
if (rectList.get(i).getX() < 0) { //判断方块是否撞墙
int flag = rectList.get(i).getFlag() + 1;
rectList.get(i).setFlag(flag);
}
}
}
mainframe.repaint(); //界面重绘
try {
Thread.sleep(100); //线程休眠
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
运行示意图:方块在碰撞到界面边缘时会改变路径返回,并且flag标志位加1。