在java中使用线程实现runnable时,形状没有移动

在java中使用线程实现runnable时,形状没有移动,java,multithreading,swing,awt,Java,Multithreading,Swing,Awt,我有一段代码,当实现runnable类时,椭圆形应该自动向右移动。然而,它似乎没有移动。非常感谢您的帮助。提前谢谢 package movingball; import java.awt.Color; import java.awt.Graphics; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.JFrame; import javax.swing.JPanel; pu

我有一段代码,当实现runnable类时,椭圆形应该自动向右移动。然而,它似乎没有移动。非常感谢您的帮助。提前谢谢

package movingball;

import java.awt.Color;
import java.awt.Graphics;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class MovingBall extends JPanel{

    private static final int x = 30;
    private static final int y = 30;

    public MovingBall(){
        setBackground(Color.BLACK);
    }
    public MovingBall(int x, int y){
        x = this.x;
        y = this.y;  
        repaint();
    }
    public static void main(String[] args) {
        JFrame frame = new JFrame();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500,700);

        MovingBall movingBall = new MovingBall();
        frame.add(movingBall);       
        frame.setVisible(true);
调用线程以指定ball对象

        BallUsingThread ball =  new BallUsingThread(x, y);
        Thread first = new Thread(ball);
        first.start();

    }

    @Override
    public void paintComponent(Graphics canvas){
        super.paintComponent(canvas);

        canvas.setColor(Color.BLUE);
        canvas.fillOval(x, y, 100, 100);
    }

}
/*Here is the second class. Where the oval shape should be moving. Any `suggestions here? Also just let me know if there are some codes need to be adjusted.*/

    class BallUsingThread implements Runnable{
        int x = 30;
        int y = 30;

        public BallUsingThread(int x, int y){
            this.x  = x;
            this.y = y;
        }
        @Override
        public void run() {
            for(;;){
                x++;
                try {
                    Thread.sleep(2000);
                } catch (InterruptedException ex) {
                    System.out.printf("Error",ex);
                }
            }
        }

    }

您的线程只需更新程序内存(在每个阶段它都会递增
x
)。windowing子系统不知道组件的脏状态,因此不会调用paint方法

您必须调用
JComponent.repaint()
,请注意,调用必须在UI线程中进行(例如,通过使用
SwingUtilities.invokeLater()


请注意,以这种方式,您的程序没有任何机会平稳运行,并且会导致大量CPU周期的中断。对于动画和/或游戏,您需要一个活套,它可以让您在一秒钟内控制帧的运行时间和帧数。

您的线程只需更新程序内存(在每个阶段它都会增加
x
)。windowing子系统不知道组件的脏状态,因此不会调用paint方法

您必须调用
JComponent.repaint()
,请注意,调用必须在UI线程中进行(例如,通过使用
SwingUtilities.invokeLater()

请注意,以这种方式,您的程序没有任何机会平稳运行,并且会导致大量CPU周期的中断。对于动画和/或游戏,您需要一个活套,它可以让您在一秒钟内控制帧的运行时间和帧数。

private static final int x = 30;
private static final int y = 30;
class BallUsingThread implements Runnable{
    int x = 30;
    int y = 30;

    public BallUsingThread(int x, int y){
        this.x  = x;
        this.y = y;
    }
    @Override
    public void run() {
        for(;;){
            x++;
使值不变

这个

private static final int x = 30;
private static final int y = 30;
class BallUsingThread implements Runnable{
    int x = 30;
    int y = 30;

    public BallUsingThread(int x, int y){
        this.x  = x;
        this.y = y;
    }
    @Override
    public void run() {
        for(;;){
            x++;
是个毫无意义的人。由于Java传递变量的方式,对值
x
的任何修改只会在
ball的上下文中使用read
类进行,
MovingBall
将看不到它们,即使您可以让它重新绘制

相反,您可能应该将
MovingBall
的引用传递给
ballusingtread
,并提供一个
ballusingtread
调用的方法,该方法更新球的
x
位置,例如

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class MovingBall extends JPanel {

    private int ballX = 30;
    private int ballY = 30;

    public MovingBall() {
        setBackground(Color.BLACK);
    }

    public MovingBall(int x, int y) {
        x = this.ballX;
        y = this.ballY;
        repaint();
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 700);

        MovingBall movingBall = new MovingBall();
        frame.add(movingBall);
        frame.setVisible(true);

        BallUsingThread ball = new BallUsingThread(movingBall);
        Thread first = new Thread(ball);
        first.start();

    }

    @Override
    public void paintComponent(Graphics canvas) {
        super.paintComponent(canvas);

        canvas.setColor(Color.BLUE);
        canvas.fillOval(ballX, ballY, 100, 100);
    }

    public void updateBall() {
        if (EventQueue.isDispatchThread()) {
            ballX++;
            repaint();
        } else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    updateBall();
                }
            });
        }
    }

}

/*Here is the second class. Where the oval shape should be moving. Any `suggestions here? Also just let me know if there are some codes need to be adjusted.*/
class BallUsingThread implements Runnable {

    private MovingBall movingBall;

    public BallUsingThread(MovingBall mb) {
        movingBall = mb;
    }

    @Override
    public void run() {
        for (;;) {
            movingBall.updateBall();
            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {
                System.out.printf("Error", ex);
            }
        }
    }

}
现在,Swing不是线程安全的(我已经说明了这一点),但是有一个更简单的解决方案

改用Swing
定时器

MovingBall
BallUsingTimer
有关更多详细信息,请参见和

private static final int x = 30;
private static final int y = 30;
class BallUsingThread implements Runnable{
    int x = 30;
    int y = 30;

    public BallUsingThread(int x, int y){
        this.x  = x;
        this.y = y;
    }
    @Override
    public void run() {
        for(;;){
            x++;
使值不变

这个

private static final int x = 30;
private static final int y = 30;
class BallUsingThread implements Runnable{
    int x = 30;
    int y = 30;

    public BallUsingThread(int x, int y){
        this.x  = x;
        this.y = y;
    }
    @Override
    public void run() {
        for(;;){
            x++;
是个毫无意义的人。由于Java传递变量的方式,对值
x
的任何修改只会在
ball的上下文中使用read
类进行,
MovingBall
将看不到它们,即使您可以让它重新绘制

相反,您可能应该将
MovingBall
的引用传递给
ballusingtread
,并提供一个
ballusingtread
调用的方法,该方法更新球的
x
位置,例如

import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class MovingBall extends JPanel {

    private int ballX = 30;
    private int ballY = 30;

    public MovingBall() {
        setBackground(Color.BLACK);
    }

    public MovingBall(int x, int y) {
        x = this.ballX;
        y = this.ballY;
        repaint();
    }

    public static void main(String[] args) {
        JFrame frame = new JFrame();

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setSize(500, 700);

        MovingBall movingBall = new MovingBall();
        frame.add(movingBall);
        frame.setVisible(true);

        BallUsingThread ball = new BallUsingThread(movingBall);
        Thread first = new Thread(ball);
        first.start();

    }

    @Override
    public void paintComponent(Graphics canvas) {
        super.paintComponent(canvas);

        canvas.setColor(Color.BLUE);
        canvas.fillOval(ballX, ballY, 100, 100);
    }

    public void updateBall() {
        if (EventQueue.isDispatchThread()) {
            ballX++;
            repaint();
        } else {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    updateBall();
                }
            });
        }
    }

}

/*Here is the second class. Where the oval shape should be moving. Any `suggestions here? Also just let me know if there are some codes need to be adjusted.*/
class BallUsingThread implements Runnable {

    private MovingBall movingBall;

    public BallUsingThread(MovingBall mb) {
        movingBall = mb;
    }

    @Override
    public void run() {
        for (;;) {
            movingBall.updateBall();
            try {
                Thread.sleep(500);
            } catch (InterruptedException ex) {
                System.out.printf("Error", ex);
            }
        }
    }

}
现在,Swing不是线程安全的(我已经说明了这一点),但是有一个更简单的解决方案

改用Swing
定时器

MovingBall
BallUsingTimer

查看和了解更多详细信息

repaint
实际上是少数线程安全方法中的一种,但是
MovingBall
将永远看不到
ballUsingRead
x
所做的更改,因此它无论如何都是毫无意义的。我不知道。感谢
repaint
实际上是为数不多的线程安全方法之一,但是
MovingBall
将永远看不到
ballusingtread
x
所做的更改,所以它无论如何都是毫无意义的。谢谢