Java小项目——多线程弹球

一、需求分析

版本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);

结果:

原文地址:https://www.cnblogs.com/iriswang/p/11084646.html