Java 我能';我看不到圆在移动
在java中使用Swing时,我试图在单击按钮时将圆从起始位置缓慢移动到结束位置。然而,我看不到圆圈在移动。它只是在瞬间从开始移动到结束Java 我能';我看不到圆在移动,java,swing,awt,Java,Swing,Awt,在java中使用Swing时,我试图在单击按钮时将圆从起始位置缓慢移动到结束位置。然而,我看不到圆圈在移动。它只是在瞬间从开始移动到结束 import javax.swing.*; import java.awt.*; import java.awt.event.*; public class MyApp { private int x = 10; private int y = 10; private JFrame f; private MyDraw m;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class MyApp {
private int x = 10;
private int y = 10;
private JFrame f;
private MyDraw m;
private JButton b;
public void go() {
f = new JFrame("Moving circle");
b = new JButton("click me to move circle");
m = new MyDraw();
f.add(BorderLayout.SOUTH, b);
f.add(BorderLayout.CENTER, m);
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
b.addActionListener(new Bute());
}
public static void main(String[] args) {
MyApp m = new MyApp();
m.go();
}
private class Bute implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
for (int i = 0; i < 150; i++) {
++x;
++y;
m.repaint();
Thread.sleep(50);
}
}
}
private class MyDraw extends JPanel {
@Override
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, 500, 500);
g.setColor(Color.red);
g.fillOval(x, y, 40, 40);
}
}
}
import javax.swing.*;
导入java.awt.*;
导入java.awt.event.*;
公共类MyApp{
私人整数x=10;
私人智力y=10;
私有jf框架;
私人密室;
私人JButton b;
公开作废go(){
f=新JFrame(“移动圆”);
b=新的JButton(“单击我移动圆圈”);
m=新的MyDraw();
f、 添加(BorderLayout.SOUTH,b);
f、 添加(BorderLayout.CENTER,m);
f、 设置大小(500500);
f、 setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f、 setVisible(真);
b、 addActionListener(新Bute());
}
公共静态void main(字符串[]args){
MyApp m=新的MyApp();
m、 go();
}
私有类Bute实现ActionListener{
@凌驾
已执行的公共无效操作(操作事件e){
对于(int i=0;i<150;i++){
++x;
++y;
m、 重新油漆();
睡眠(50);
}
}
}
私有类MyDraw扩展了JPanel{
@凌驾
公共组件(图形g){
g、 setColor(Color.white);
g、 fillRect(0,0500500);
g、 setColor(Color.red);
g、 椭圆形(x,y,40,40);
}
}
}
我认为问题在于动作监听器,因为当我不使用按钮的时候,它就工作了。有什么建议吗?正如Andrew Thompson所说,调用
Thread.sleep()
而不定义第二个线程会冻结所有内容,因此解决方案是定义并运行另一个线程,如下所示:
class Bute implements ActionListener, Runnable {
//let class implement Runnable interface
Thread t; // define 2nd thread
public void actionPerformed(ActionEvent e) {
t = new Thread(this); //start a new thread
t.start();
}
@Override //override our thread's run() method to do what we want
public void run() { //this is after some java-internal init stuff called by start()
//b.setEnabled(false);
for (int i = 0; i < 150; i++) {
x++;
y++;
m.repaint();
try {
Thread.sleep(50); //let the 2nd thread sleep
} catch (InterruptedException iEx) {
iEx.printStackTrace();
}
}
//b.setEnabled(true);
}
}
class Bute实现ActionListener,可运行{
//让类实现可运行接口
线程t;//定义第二个线程
已执行的公共无效操作(操作事件e){
t=新线程(this);//启动新线程
t、 start();
}
@Override//Override我们线程的run()方法来执行我们想要的操作
public void run(){//这是在start()调用的一些java内部init之后
//b、 setEnabled(假);
对于(int i=0;i<150;i++){
x++;
y++;
m、 重新油漆();
试一试{
Thread.sleep(50);//让第二个线程睡眠
}捕获(中断异常iEx){
iEx.printStackTrace();
}
}
//b、 setEnabled(真);
}
}
此解决方案的唯一问题是,多次按下按钮将加快圆的速度,但可以通过
b.setEnabled(true/false)
在动画期间使按钮不可点击来解决此问题。这不是最好的解决方案,但它很有效。正如Andrew Thompson所说,在不定义第二个线程的情况下调用Thread.sleep()
会冻结所有内容,因此解决方案是定义并运行另一个线程,如下所示:
class Bute implements ActionListener, Runnable {
//let class implement Runnable interface
Thread t; // define 2nd thread
public void actionPerformed(ActionEvent e) {
t = new Thread(this); //start a new thread
t.start();
}
@Override //override our thread's run() method to do what we want
public void run() { //this is after some java-internal init stuff called by start()
//b.setEnabled(false);
for (int i = 0; i < 150; i++) {
x++;
y++;
m.repaint();
try {
Thread.sleep(50); //let the 2nd thread sleep
} catch (InterruptedException iEx) {
iEx.printStackTrace();
}
}
//b.setEnabled(true);
}
}
class Bute实现ActionListener,可运行{
//让类实现可运行接口
线程t;//定义第二个线程
已执行的公共无效操作(操作事件e){
t=新线程(this);//启动新线程
t、 start();
}
@Override//Override我们线程的run()方法来执行我们想要的操作
public void run(){//这是在start()调用的一些java内部init之后
//b、 setEnabled(假);
对于(int i=0;i<150;i++){
x++;
y++;
m、 重新油漆();
试一试{
Thread.sleep(50);//让第二个线程睡眠
}捕获(中断异常iEx){
iEx.printStackTrace();
}
}
//b、 setEnabled(真);
}
}
此解决方案的唯一问题是,多次按下按钮将加快圆的速度,但可以通过
b.setEnabled(true/false)
在动画期间使按钮不可点击来解决此问题。这不是最好的解决方案,但很有效。正如评论和另一个答案中所说的,不要阻止EDTThead.sleep(…)
将阻止它,因此您有两个选项:
- 创建和管理您自己的(新)线程
- 挥杆
计时器,因为它更容易使用。我还将paintComponent
方法更改为使用Shape
API,并相应地将按钮文本更改为开始和停止,以及对按钮和计时器重复使用相同的ActionListener
:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class MovingCircle {
private JFrame frame;
private CustomCircle circle;
private Timer timer;
private JButton button;
public static void main(String[] args) {
SwingUtilities.invokeLater(new MovingCircle()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(this.getClass().getSimpleName());
circle = new CustomCircle(Color.RED);
timer = new Timer(100, listener);
button = new JButton("Start");
button.addActionListener(listener);
circle.setBackground(Color.WHITE);
frame.add(circle);
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private ActionListener listener = (e -> {
if (!timer.isRunning()) {
timer.start();
button.setText("Stop");
} else {
if (e.getSource().equals(button)) {
timer.stop();
button.setText("Start");
}
}
circle.move(1, 1);
});
@SuppressWarnings("serial")
class CustomCircle extends JPanel {
private Color color;
private int circleX;
private int circleY;
public CustomCircle(Color color) {
this.color = color;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(color);
g2d.fill(new Ellipse2D.Double(circleX, circleY, 50, 50));
}
@Override
public Dimension preferredSize() {
return new Dimension(100, 100);
}
public void move(int xGap, int yGap) {
circleX += xGap;
circleY += yGap;
revalidate();
repaint();
}
public int getCircleX() {
return circleX;
}
public void setCircleX(int circleX) {
this.circleX = circleX;
}
public int getCircleY() {
return circleY;
}
public void setCircleY(int circleY) {
this.circleY = circleY;
}
}
}
很抱歉,我无法发布我想要的GIF,但此示例按预期运行。如评论和另一个答案中所述,不要阻止EDTThead.sleep(…)
将阻止它,因此您有两个选项:
- 创建和管理您自己的(新)线程
- 挥杆
在这个答案中,我将使用Swing计时器,因为它更容易使用。我还将paintComponent
方法更改为使用Shape
API,并相应地将按钮文本更改为开始和停止,以及对按钮和计时器重复使用相同的ActionListener
:
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionListener;
import java.awt.geom.Ellipse2D;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
public class MovingCircle {
private JFrame frame;
private CustomCircle circle;
private Timer timer;
private JButton button;
public static void main(String[] args) {
SwingUtilities.invokeLater(new MovingCircle()::createAndShowGui);
}
private void createAndShowGui() {
frame = new JFrame(this.getClass().getSimpleName());
circle = new CustomCircle(Color.RED);
timer = new Timer(100, listener);
button = new JButton("Start");
button.addActionListener(listener);
circle.setBackground(Color.WHITE);
frame.add(circle);
frame.add(button, BorderLayout.SOUTH);
frame.pack();
frame.setVisible(true);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
}
private ActionListener listener = (e -> {
if (!timer.isRunning()) {
timer.start();
button.setText("Stop");
} else {
if (e.getSource().equals(button)) {
timer.stop();
button.setText("Start");
}
}
circle.move(1, 1);
});
@SuppressWarnings("serial")
class CustomCircle extends JPanel {
private Color color;
private int circleX;
private int circleY;
public CustomCircle(Color color) {
this.color = color;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g;
g2d.setColor(color);
g2d.fill(new Ellipse2D.Double(circleX, circleY, 50, 50));
}
@Override
public Dimension preferredSize() {
return new Dimension(100, 100);
}
public void move(int xGap, int yGap) {
circleX += xGap;
circleY += yGap;
revalidate();
repaint();
}
public int getCircleX() {
return circleX;
}
public void setCircleX(int circleX) {
this.circleX = circleX;
}
public int getCircleY() {
return circleY;
}
public void setCircleY(int circleY) {
this.circleY = circleY;
}
}
}
很抱歉,我无法发布我想要的GIF,但此示例按预期运行。我推荐一位眼镜商。不要阻止EDT(事件调度线程)。发生这种情况时,GUI将“冻结”。有关详细信息和修复方法,请参阅。我推荐一位眼镜商。不要阻止EDT(事件调度线程)。发生这种情况时,GUI将“冻结”。有关详细信息和修复方法,请参见。public void go(){JFrame frame=new JFrame();frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);MyDrawPanel drawPanel=new MyDrawPanel();frame.setSize(300300);frame.setVisible(true);用于