一、需求分析
版本V1:多线程绘制小球
版本V2:开启一个线程,绘制队列listBall内多个小球
版本V3:使用启动和暂停按钮,控制线程小球的运动
二、版本V1:多线程绘制小球
点击绘制区域,获取x和y的坐标;
创建和开始一个线程,线程中run()函数中内容为绘制小球;
小球绘制卸载for循环内,每次加上速度v,更新坐标。
UI页面类:
package com.java8.threadballV1;
import javax.swing.*;
import java.awt.*;
public class BallFrame {
public static void main(String[] arg){
BallFrame bf = new BallFrame();
bf.showUI();
}
private void showUI() {
JFrame jf = new JFrame();
jf.setName("线程小球V1");
jf.setSize(500,600);
jf.setDefaultCloseOperation(3);
jf.setLocationRelativeTo(null);
JPanel jp_control = new JPanel();
JPanel jp_ball = new JPanel();
jp_control.setBackground(Color.lightGray);
jp_ball.setBackground(Color.white);
jf.add(jp_control,BorderLayout.NORTH);
jf.add(jp_ball,BorderLayout.CENTER);
JButton jb = new JButton("run");
jp_control.add(jb);
jf.setVisible(true);
Graphics g = jp_ball.getGraphics();
ThreadListener threadListener = new ThreadListener(g);
jp_ball.addMouseListener(threadListener);
jb.addActionListener(threadListener);
}
}
监听器类:
点击屏幕,启动线程,thread.start(),启动重写后的run()函数
package com.java8.threadballV1;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
public class ThreadListener extends MouseAdapter implements ActionListener {
private Graphics g;
public ThreadListener(Graphics g) {
this.g = g;
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("run");
}
@Override
public void mouseClicked(MouseEvent e) {
int x = e.getX();
int y = e.getY();
BallThread ballThread = new BallThread(g,x,y);
ballThread.start();
}
}
触发器类:
重写run()函数:循环绘制小球,每次x,y分别加上v。
package com.java8.threadballV1;
import java.awt.*;
public class BallThread extends Thread {
private Graphics g;
int x;
int y;
int v = 1;
public BallThread(Graphics g,int x,int y){
this.g = g;
this.x = x;
this.y = y;
}
@Override
public void run() {
for (int i = 0; i < 200; i++) {
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
x += v;
y += v;
g.setColor(Color.orange);
g.fillOval(x, y, 20, 20);
}
}
}
二、版本V2:开启一个线程,绘制队列listBall内多个小球
1、Ball类:增加该类别,存储小球与ArrayList<Ball> listBall内,用于在线程中绘制。
存储了ball的属性:x和y
包含了绘制ball的代码:考虑了撞墙的情况
package com.java8.threadballV2;
import javax.swing.*;
import java.awt.*;
public class Ball {
private int x, y;
private int radius = 30;
private int vx = 3, vy = 3;
public Ball(int x, int y) {
this.x = x;
this.y = y;
}
public void drawBall(Graphics g, JPanel jp_ball) {
//1.判断是否为边界
if (x <= 0 || x + radius >= jp_ball.getWidth()) {
vx = -vx;
}
if (y <= 0 || y + radius >= jp_ball.getHeight()) {
vy = -vy;
}
//2.绘制一个背景色小球,覆盖于上次绘制的小球上
g.setColor(Color.white);
g.fillOval(x, y, radius, radius);
//3.获取本次的x和y
x += vx;
y += vy;
//4.绘制本次小球
g.setColor(Color.orange);
g.fillOval(x, y, radius, radius);
}
}
2、BallListener:点击时,生成ball对象,存入listBall
构造方法中:
若线程不存在,则创建线程,传入画笔g、画布jp_ball、队列listBall
mouseClick中:
每点击一次,则生成一个ball对象;
将ball对象add如队列listBall中。
package com.java8.threadballV2;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
public class ThreadListener extends MouseAdapter implements ActionListener {
private int x,y;
//JPanel:用于获取画笔的长和宽
private JPanel jp_ball;
//队列:存储球的对象,不用定义初始长度
private ArrayList<Ball> listBall = new ArrayList<Ball>();
//线程:线程中循环绘制listBall中的所有ball
private BallThread ballThread;
public ThreadListener(Graphics g,JPanel jp_ball) {
this.jp_ball = jp_ball;
//构造函数只使用1次,在此处创建线程,则线程一定只有一个——实现一个线程绘制多个小球
//创建线程对象,构造方法将画笔和画布和队列listBall传入
if(ballThread==null){
System.out.println("线程创建");
ballThread = new BallThread(g,listBall,jp_ball);
ballThread.start();
}
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("run");
}
@Override
public void mouseClicked(MouseEvent e) {
// 1.获取x和y
x = e.getX();
y = e.getY();
// 2.判断点击是否超出界面,超出则把其设置为边界x和y
if (x + 20 >= jp_ball.getWidth()){
x = jp_ball.getWidth() - 30;
}
if (y + 20 >= jp_ball.getHeight()){
y = jp_ball.getHeight() - 30;
}
// 3.点击时,创建小球对象,
Ball ball = new Ball(x,y);
// 4.将小球对象存入小球队列listBall中
listBall.add(ball);
}
}
3、BallThread:重写的run(),循环调用listBall中ball的drawBall绘制方法
package com.java8.threadballV2;
import javax.swing.*;
import java.awt.*;
import java.util.ArrayList;
public class BallThread extends Thread {
private Graphics g;
private JPanel jp_ball;
private ArrayList<Ball> listBall;
public BallThread(Graphics g,ArrayList<Ball> listBall,JPanel jp_ball){
this.g = g;
this.listBall = listBall;
this.jp_ball = jp_ball;
}
@Override
public void run() {
while(true){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
for (int i=0;i<listBall.size();i++){
listBall.get(i).drawBall(g,jp_ball);
}
}
}
}
4、BallFrame中:仅仅在创建监听器时,多传入jp_ball对象
ThreadListener threadListener = new ThreadListener(g,jp_ball);
结果: