Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用多线程更新GUI_Java_Multithreading_Swing_Animation_Custom Painting - Fatal编程技术网

Java 使用多线程更新GUI

Java 使用多线程更新GUI,java,multithreading,swing,animation,custom-painting,Java,Multithreading,Swing,Animation,Custom Painting,我正在学习使用java线程,所以我决定制作一个简单的弹跳球程序。 然而,程序显示多个线程,但只有一个线程利用了窗口大小,其他球仅限于一个区域 我试着为每个球的JPanel和不同的布局设置大小,但都不起作用 BouncingBall.java import java.awt.*; 导入java.awt.event.ActionEvent; 导入java.awt.event.ActionListener; 导入java.awt.event.MouseEvent; 导入java.awt.event.M

我正在学习使用java线程,所以我决定制作一个简单的弹跳球程序。 然而,程序显示多个线程,但只有一个线程利用了窗口大小,其他球仅限于一个区域

我试着为每个球的JPanel和不同的布局设置大小,但都不起作用

BouncingBall.java

import java.awt.*;
导入java.awt.event.ActionEvent;
导入java.awt.event.ActionListener;
导入java.awt.event.MouseEvent;
导入java.awt.event.MouseListener;
导入java.util.ArrayList;
导入javax.swing.*;
公共类BouncingBall扩展JFrame{
ArrayList balls=新的ArrayList();
//GUI元素
JLabel-lblCount;
JButton btn=新JButton(“停止”);
弹跳球{
//设置DefaultLookandFeelDecorated(true);
片名(“弹跳球”);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
设置大小(300200);
对于(int i=0;i<5;i++){
添加(新的Ball());
}
setLayout(新的FlowLayout());
setContentPane(balls.get(0));
get(0.init();
b:球
) {
System.out.println(b.getHeight());
如果(b!=balls.get(0)){
b、 init();
获取(0)并添加(b);
}
}
添加(btn,BorderLayout.SOUTH);
btn.addActionListener(新ActionListener(){
@凌驾
已执行的公共无效操作(操作事件e){
b:球
) {
b、 停止移动();
}
}
});
addMouseListener(新MouseListener(){
@凌驾
公共无效mouseClicked(MouseEvent e){
b:球
) {
b、 开始移动();
}
}
@凌驾
公共无效鼠标按下(MouseEvent e){
}
@凌驾
公共无效MouseEvent(MouseEvent e){
}
@凌驾
公共无效鼠标事件(鼠标事件e){
}
@凌驾
公共无效mouseExited(MouseEvent e){
}
});
此.setVisible(true);
}
公共静态void main(字符串[]args){
新弹跳球();
}
}
Ball.java


导入javax.swing.*;
导入java.awt.*;
公共类Ball扩展JPanel实现Runnable{
//盒子的高度和宽度
整数宽度;
内部高度;
//球大小
浮动半径=5;
浮子直径=半径*2;
//呼叫中心
浮动X=半径+50;
浮动Y=半径+20;
//方向
浮动dx;
浮动dy;
//瓦尔斯
整数计数=0;
float[]colorHSB=新浮点[3];
布尔移动=假;
//线
螺纹t;
Ball(){
dx=(float)Math.random()*10;
dy=(float)Math.random()*10;
宽度=getWidth();
高度=getHeight();
对于(int i=0;i<3;i++){
colorHSB[i]=(float)Math.random()*255;
}
t=新螺纹(本螺纹);
}
void init(){
t、 start();
}
公开募捐{
while(true){
宽度=getWidth();
高度=getHeight();
如果(移动){
X=X+dx;
Y=Y+dy;
}
如果(X-半径<0){
dx=-dx;
X=半径;
addCount();
}否则如果(X+半径>宽度){
dx=-dx;
X=宽度-半径;
addCount();
}
如果(Y-半径<0){
dy=-dy;
Y=半径;
addCount();
}如果((Y+半径)>高度),则为其他情况{
dy=-dy;
Y=高度-半径;
addCount();
}
重新油漆();
试一试{
睡眠(50);
}捕获(中断异常例外){
}
}
}
公共无效开始移动(){
移动=真;
}
公共空间停止移动(){
移动=假;
}
公共组件(图形g){
超级组件(g);
g、 setColor(Color.getHSBColor(colorHSB[0],colorHSB[1],colorHSB[2]);
g、 椭圆((int)(X-半径),(int)(Y-半径),(int)直径,(int)直径);
}
公共void addCount(){
计数++;
系统输出打印项次(计数);
}
}
程序运行的照片

它应该显示利用整个窗口在帧周围反弹的所有球。

我的答案基于。这将在模型、视图和控制器之间划分责任。
每一个(M、V和C)都成为定义明确的单一责任类别。 起初,类的数量以及它们之间的关系可能看起来令人费解。在研究和理解了这个结构之后,你意识到它实际上把你试图解决的“问题”分成了更小、更容易处理的部分

球可以是模型的简单示例。它实际上是一个pojo,保存视图绘制球所需的所有信息:

//a model representing ball
class Ball  {

    //Ball attributes
    private static final int SIZE = 10;  //diameter
    private int x, y;  // Position
    private final Color color;
    private Observer observer;  //to be notified on changes

    Ball() {

        Random rnd = new Random();
        color = new Color(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
    }

    Color getColor() {
        return color;
    }

    int getSize(){
        return SIZE;
    }

    synchronized int getX() {
        return x;
    }

    synchronized void setX(int x) {
        this.x = x;
        notifyObserver();
    }

    synchronized int getY() {
        return y;
    }

    synchronized void setY(int y) {
        this.y = y;
        notifyObserver();
    }

    void registerObserver(Observer observer){
        this.observer = observer;
    }

    void notifyObserver(){
        if(observer == null) return;
        observer.onObservableChanged();
    }
}
请注意,您可以将
观察者
注册到
观察者的定义如下:

//listening interface. Implemented by View and used by Ball to notify changes
interface Observer {
    void onObservableChanged();
}
球用它来通知观察者发生了变化。 一个
Ball
还有一些
synchronized
getter和setter,因此它的属性可以被多个线程访问。

我们还应该定义一个
模型
,另一个pojo,它是封装视图需要的所有信息的类:

//view model: hold info that view needs
class Model {

    private final ArrayList<Ball> balls;
    private final int width, height;

    Model(){
        balls = new ArrayList<>();
        width = 300; height = 200;
    }

    boolean addBall(Ball ball){
        return balls.add(ball);
    }

    List<Ball> getBalls() {
        return new ArrayList<>(balls); //return a copy of balls
    }

    int getWidth() {
        return width;
    }

    int getHeight() {
        return height;
    }
}
请注意,
视图(实际上是
BallsPane
)实现了
Observer
。它将观察(或倾听)球的变化,并对其作出响应
class View {

    private final BallsPane ballsPane;

    View(Model model){
        ballsPane = new BallsPane(model);
    }

    void createAndShowGui(){
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.add(ballsPane);
        frame.pack();
        frame.setResizable(false);
        frame.setVisible(true);
    }

    Observer getObserver(){
        return ballsPane;
    }
}

class BallsPane extends JPanel implements Observer {

    private final Model model;

    BallsPane(Model model){
        this.model = model;
        setPreferredSize(new Dimension(model.getWidth(), model.getHeight()));
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        for(Ball b : model.getBalls()){
            g.setColor(b.getColor());
            g.fillOval(b.getX(), b.getY(), b.getSize(), b.getSize());
        }
    }

    @Override
    public void onObservableChanged() {
        repaint(); //when a change was notified
    }
}
class BallAnimator implements Runnable{

    private final Ball ball;
    private final int maxX, maxY;
    private final Random rnd;
    private boolean moveRight = true,  moveDown = true;
    private static final int STEP =1, WAIT = 40;

    BallAnimator(Ball ball, int maxX, int maxY) {
        this.ball = ball;
        this.maxX = maxX;
        this.maxY = maxY;
        rnd = new Random();
        ball.setX(rnd.nextInt(maxX - ball.getSize()));
        ball.setY(rnd.nextInt(maxY - ball.getSize()));
        new Thread(this).start();
    }

    @Override
    public void run() {

        while(true){

            int dx = moveRight ? STEP : -STEP ;
            int dy = moveDown  ? STEP : -STEP ;

            int newX = ball.getX() + dx;
            int newY = ball.getY() + dy;

            if(newX + ball.getSize()>= maxX || newX <= 0){
                newX = ball.getX() - dx;
                moveRight = ! moveRight;
            }

            if(newY +ball.getSize()>= maxY || newY <= 0){
                newY = ball.getY() - dy;
                moveDown = ! moveDown;
            }

            ball.setX(newX);
            ball.setY(newY);

            try {
                Thread.sleep(WAIT);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }
}
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class BouncingBalls{

    BouncingBalls(int numOfBalls) {

        Model model = new Model();
        View view = new View(model);;

        for (int i = 0; i < numOfBalls; i++) {
            Ball b = new Ball(); //construct  a ball
            model.addBall(b);    //add it to the model 
            b.registerObserver(view.getObserver());  //register view as an observer to it 
            new BallAnimator(b, model.getWidth(), model.getHeight()); //start a thread to update it 
        }

        view.createAndShowGui();
    }

    public static void main(String[] args) {
        new BouncingBalls(5);
    }
}

//listening interface. Implemented by View and used by Ball to notify changes
interface Observer {
    void onObservableChanged();
}

class View {

    private final BallsPane ballsPane;

    View(Model model){
        ballsPane = new BallsPane(model);
    }

    void createAndShowGui(){
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.add(ballsPane);
        frame.pack();
        frame.setResizable(false);
        frame.setVisible(true);
    }

    Observer getObserver(){
        return ballsPane;
    }
}

class BallsPane extends JPanel implements Observer {

    private final Model model;

    BallsPane(Model model){
        this.model = model;
        setPreferredSize(new Dimension(model.getWidth(), model.getHeight()));
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        for(Ball b : model.getBalls()){
            g.setColor(b.getColor());
            g.fillOval(b.getX(), b.getY(), b.getSize(), b.getSize());
        }
    }

    @Override
    public void onObservableChanged() {
        repaint(); //when a change was notified
    }
}

//view model: hold info that view needs
class Model {

    private final ArrayList<Ball> balls;
    private final int width, height;

    Model(){
        balls = new ArrayList<>();
        width = 300; height = 200;
    }

    boolean addBall(Ball ball){
        return balls.add(ball);
    }

    List<Ball> getBalls() {
        return new ArrayList<>(balls); //return a copy of balls
    }

    int getWidth() {
        return width;
    }

    int getHeight() {
        return height;
    }
}

//a model representing ball
class Ball  {

    //Ball attributes
    private static final int SIZE = 10;  //diameter
    private int x, y;  // Position
    private final Color color;
    private Observer observer;  //to be notified on changes

    Ball() {

        Random rnd = new Random();
        color = new Color(rnd.nextInt(256), rnd.nextInt(256), rnd.nextInt(256));
    }

    Color getColor() {
        return color;
    }

    int getSize(){
        return SIZE;
    }

    synchronized int getX() {
        return x;
    }

    synchronized void setX(int x) {
        this.x = x;
        notifyObserver();
    }

    synchronized int getY() {
        return y;
    }

    synchronized void setY(int y) {
        this.y = y;
        notifyObserver();
    }

    void registerObserver(Observer observer){
        this.observer = observer;
    }

    void notifyObserver(){
        if(observer == null) return;
        observer.onObservableChanged();
    }
}

class BallAnimator implements Runnable{

    private final Ball ball;
    private final int maxX, maxY;
    private final Random rnd;
    private boolean moveRight = true,  moveDown = true;
    private static final int STEP =1, WAIT = 40;

    BallAnimator(Ball ball, int maxX, int maxY) {
        this.ball = ball;
        this.maxX = maxX;
        this.maxY = maxY;
        rnd = new Random();
        ball.setX(rnd.nextInt(maxX - ball.getSize()));
        ball.setY(rnd.nextInt(maxY - ball.getSize()));
        new Thread(this).start();
    }

    @Override
    public void run() {

        while(true){

            int dx = moveRight ? STEP : -STEP ;
            int dy = moveDown  ? STEP : -STEP ;

            int newX = ball.getX() + dx;
            int newY = ball.getY() + dy;

            if(newX + ball.getSize()>= maxX || newX <= 0){
                newX = ball.getX() - dx;
                moveRight = ! moveRight;
            }

            if(newY +ball.getSize()>= maxY || newY <= 0){
                newY = ball.getY() - dy;
                moveDown = ! moveDown;
            }

            ball.setX(newX);
            ball.setY(newY);

            try {
                Thread.sleep(WAIT);
            } catch (InterruptedException ex) {
                ex.printStackTrace();
            }
        }
    }
}