在 java 实现 runnable 中使用线程时形状没有移动
The shape is not moving when using thread in java implementing runnable
我有这段代码,椭圆形在实现可运行对象时应该自动向右移动class。然而它似乎没有动。任何帮助深表感谢。提前致谢。
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);
调用线程分配球对象
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
)。窗口子系统不知道组件的脏状态,所以不调用 paint 方法。
您必须调用 JComponent.repaint()
,请注意调用必须发生在 UI 线程中(例如使用 SwingUtilities.invokeLater()
)。
请注意,在这种情况下,您的程序没有任何 运行 顺利的机会,并且会爆发很多 CPU 循环。对于动画 and/or 游戏,您需要一个循环器来控制帧的 运行 时间以及一秒内的帧数。
这个...
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
的任何修改只会在 BallUsingThread
class 的上下文中进行,MovingBall
将看不到他们,即使你可以让它重新粉刷。
相反,您可能应该将 MovingBall
的引用传递给 BallUsingThread
并提供一个 BallUsingThread
调用更新球的 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 Timer
...
MovingBall
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
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);
BallUsingTimer ball = new BallUsingTimer(movingBall);
Timer timer = new Timer(40, ball);
timer.start();
}
@Override
public void paintComponent(Graphics canvas) {
super.paintComponent(canvas);
canvas.setColor(Color.BLUE);
canvas.fillOval(ballX, ballY, 100, 100);
}
public void updateBall() {
ballX++;
repaint();
}
}
BallUsingTimer
public class BallUsingTimer implements ActionListener {
private MovingBall movingBall;
public BallUsingTimer(MovingBall mb) {
movingBall = mb;
}
@Override
public void actionPerformed(ActionEvent e) {
movingBall.updateBall();
}
}
有关详细信息,请参阅 Concurrency in Swing and How to use Swing Timers
我有这段代码,椭圆形在实现可运行对象时应该自动向右移动class。然而它似乎没有动。任何帮助深表感谢。提前致谢。
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);
调用线程分配球对象
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
)。窗口子系统不知道组件的脏状态,所以不调用 paint 方法。
您必须调用 JComponent.repaint()
,请注意调用必须发生在 UI 线程中(例如使用 SwingUtilities.invokeLater()
)。
请注意,在这种情况下,您的程序没有任何 运行 顺利的机会,并且会爆发很多 CPU 循环。对于动画 and/or 游戏,您需要一个循环器来控制帧的 运行 时间以及一秒内的帧数。
这个...
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
的任何修改只会在 BallUsingThread
class 的上下文中进行,MovingBall
将看不到他们,即使你可以让它重新粉刷。
相反,您可能应该将 MovingBall
的引用传递给 BallUsingThread
并提供一个 BallUsingThread
调用更新球的 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 Timer
...
MovingBall
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
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);
BallUsingTimer ball = new BallUsingTimer(movingBall);
Timer timer = new Timer(40, ball);
timer.start();
}
@Override
public void paintComponent(Graphics canvas) {
super.paintComponent(canvas);
canvas.setColor(Color.BLUE);
canvas.fillOval(ballX, ballY, 100, 100);
}
public void updateBall() {
ballX++;
repaint();
}
}
BallUsingTimer
public class BallUsingTimer implements ActionListener {
private MovingBall movingBall;
public BallUsingTimer(MovingBall mb) {
movingBall = mb;
}
@Override
public void actionPerformed(ActionEvent e) {
movingBall.updateBall();
}
}
有关详细信息,请参阅 Concurrency in Swing and How to use Swing Timers