本篇博客将主要介绍一个名为 Bouncing Balls App 的小程序,使用 Java 编写,主要运用了 GUI 编程和多线程的知识点。
目录
首先,我们来了解一下这个小程序做了什么。
这个小程序可以在自动生成的窗口中生成大量的彩色球,每个球都会自动以一定的速度在窗口中弹跳。
接着,我们来看一下实现这个小程序的关键代码。
# GUI 部分
图形用户界面(GUI)部分使用了 Java 原生的 Swing 库实现。
public class BouncingBallsApp extends JFrame {
private JPanel ballPanel;
private final int numBalls = 100;
private Ball[] balls;
public BouncingBallsApp() {
setTitle("Bouncing Balls Application");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setLocationRelativeTo(null);
ballPanel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (balls != null) {
for (Ball ball : balls) {
ball.draw(g);
}
}
}
};
JButton startButton = new JButton("开始");
JButton closeButton = new JButton("关闭");
// 按钮点击事件部分在下面讲解
setLayout(new BorderLayout());
add(ballPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
buttonPanel.add(startButton);
buttonPanel.add(closeButton);
add(buttonPanel, BorderLayout.SOUTH);
setVisible(true);
}
}
可以看到,通过集成 `JFrame` 类实现了一个窗口,并在其中通过 `JPanel` 类实现了一个面板,用于绘制弹跳小球。在 `paintComponent()` 方法中,通过循环遍历 `balls` 数组中的元素,调用 `draw()` 方法绘制小球。
# 多线程部分
在多线程部分中,也要自己编写一个名为 `Ball` 的类,然后实现 `Runnable` 接口(因为 Java 只支持 **单继承**,所以只能通过实现接口的方式来创建线程)。
这是 `Ball` 类的代码:
private class Ball implements Runnable {
private JPanel ballPanel;
private int x;
private int y;
private int dx;
private int dy;
private Color color;;
private static final int BALL_SIZE = 20;
public Ball(JPanel ballPanel) {
this.ballPanel = ballPanel;
Random r = new Random();
x = r.nextInt(ballPanel.getWidth() - BALL_SIZE);
y = r.nextInt(ballPanel.getHeight() - BALL_SIZE);
dx = r.nextInt(10) + 1;
dy = r.nextInt(10) + 1;
color = new Color(r.nextInt(256), r.nextInt(256), r.nextInt(256));
}
@Override
public void run() {
while (true) {
moveBall();
repaint();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void moveBall() {
if (x < 0 || x > ballPanel.getWidth() - BALL_SIZE) {
dx = -dx;
}
if (y < 0 || y > ballPanel.getHeight() - BALL_SIZE) {
dy = -dy;
}
x += dx;
y += dy;
}
private void repaint() {
ballPanel.repaint();
}
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(x, y, BALL_SIZE, BALL_SIZE);
}
}
```
然后在 `startBouncing()` 方法中,遍历 `balls` 数组中的所有元素,为每个小球(即每个 `Ball` 对象)启动一个线程,设置动画效果。
```
private void startBouncing() {
balls = new Ball[numBalls];
for (int i = 0; i < numBalls; i++) {
balls[i] = new Ball(ballPanel);
Thread thread = new Thread(balls[i]);
thread.start();
}
}
综上,本篇博客主要介绍了一个小程序 Bouncing Balls App,其中运用了 GUI 编程和多线程的知识点。如果你也想体验这个小程序,可以自己将代码编译运行后进行浏览。
下面是完整代码:
package 线程.小球页面;
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Random;
public class BouncingBallsApp extends JFrame {
private JPanel ballPanel;
private final int numBalls = 100;
private Ball[] balls;
public BouncingBallsApp() {
setTitle("Bouncing Balls Application");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setSize(800, 600);
setLocationRelativeTo(null);
ballPanel = new JPanel() {
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (balls != null) {
for (Ball ball : balls) {
ball.draw(g);
}
}
}
};
JButton startButton = new JButton("开始");
JButton closeButton = new JButton("关闭");
startButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
startBouncing();
}
});
closeButton.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});
setLayout(new BorderLayout());
add(ballPanel, BorderLayout.CENTER);
JPanel buttonPanel = new JPanel();
buttonPanel.add(startButton);
buttonPanel.add(closeButton);
add(buttonPanel, BorderLayout.SOUTH);
setVisible(true);
}
private void startBouncing() {
balls = new Ball[numBalls];
for (int i = 0; i < numBalls; i++) {
balls[i] = new Ball(ballPanel);
Thread thread = new Thread(balls[i]);
thread.start();
}
}
private class Ball implements Runnable {
private JPanel ballPanel;
private int x;
private int y;
private int dx;
private int dy;
private Color color;
private static final int BALL_SIZE = 20;
public Ball(JPanel ballPanel) {
this.ballPanel = ballPanel;
Random random = new Random();
x = random.nextInt(ballPanel.getWidth() - BALL_SIZE);
y = random.nextInt(ballPanel.getHeight() - BALL_SIZE);
dx = random.nextInt(10) + 1;
dy = random.nextInt(10) + 1;
color = new Color(random.nextInt(256), random.nextInt(256), random.nextInt(256));
}
@Override
public void run() {
while (true) {
moveBall();
repaint();
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void moveBall() {
if (x < 0 || x > ballPanel.getWidth() - BALL_SIZE) {
dx = -dx;
}
if (y < 0 || y > ballPanel.getHeight() - BALL_SIZE) {
dy = -dy;
}
x += dx;
y += dy;
}
private void repaint() {
ballPanel.repaint();
}
public void draw(Graphics g) {
g.setColor(color);
g.fillOval(x, y, BALL_SIZE, BALL_SIZE);
}
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
new BouncingBallsApp();
}
});
}
}
下面是效果展示: