我试图通过按下按钮(向上,向下,......)顺利地制作一个椭圆形的移动,我尝试在尝试中使用线程并抓住它在课堂内的工作,但是当我使用它时在这里冻结整个应用程序。
class movingdown implements ActionListener{
@Override
public void actionPerformed(ActionEvent e){
for (int i = 0; i < frame.getWidth(); i++) {
x++;
frame.repaint();
try{Thread.sleep(50);}catch(Exception ex){}
}
}
}//movingdown end
以下是我的全部代码:
package swingWork;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class movingball {
JFrame frame;
int x=0;
int y =0;
public static void main(String []args){
movingball ball = new movingball();
ball.start();
}
public void start(){
ballDrawer drawer = new ballDrawer();
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton up =new JButton("UP");
JButton down =new JButton("DOWN");
JButton left =new JButton("LEFT");
JButton right =new JButton("RIGHT");
frame.getContentPane().add(BorderLayout.NORTH, up);
frame.getContentPane().add(BorderLayout.SOUTH, down);
frame.getContentPane().add(BorderLayout.WEST, left);
frame.getContentPane().add(BorderLayout.EAST, right);
frame.getContentPane().add(BorderLayout.CENTER,drawer);
//setting up the action listener:
up.addActionListener(new movingup());
down.addActionListener(new movingdown());
left.addActionListener(new movingleft());
right.addActionListener(new movingright());
frame.setSize(300, 300);
frame.setVisible(true);
int rightsize =right.getWidth();
}//start method end
//here we have the listeners
class movingup implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
for (int i = x; i > frame.getHeight(); i--) {
x=i;
try{Thread.sleep(50);}catch(Exception ex){}
}
}
}//moving up end
class movingdown implements ActionListener{
@Override
public void actionPerformed(ActionEvent e){
for (int i = 0; i < frame.getWidth(); i++) {
x++;
frame.repaint();
try{Thread.sleep(50);}catch(Exception ex){}
}
}
}//movingdown end
class movingleft implements ActionListener{
public void actionPerformed(ActionEvent e){
x=x+10;
frame.repaint();
System.out.println(x);
}
}//moving left end
class movingright implements ActionListener{
public void actionPerformed(ActionEvent e){
}
}//moving right end
class ballDrawer extends JPanel{
@Override
public void paintComponent(Graphics g) {
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.black);
g.fillOval(x, y, 100, 100);
}//PaintComponents End
}//ball drawer class end
}//main class end
答案 0 :(得分:4)
Thread.sleep()
。 EVER !! 它永远不会完成任何好事,它会让你的屏幕冻结,直到睡眠结束。所以不要这样做!!
在Swing中制作动画的最佳方法是使用javax.swing.Timer
来触发定期更改绘图属性的事件。这发生在不同的线程上,因此屏幕保持响应。您可以将此计时器设置为始终运行,但在圆圈不应移动时不执行任何操作。这是Timer
&#39; s ActionListener
t = new Timer(TIMER_DELAY, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(deltaX == 1 && x >= frame.getWidth() - CIRCLE_WIDTH) deltaX = 0;
if(deltaY == 1 && y >= frame.getHeight() - CIRCLE_HEIGHT) deltaY = 0;
if(deltaX == -1 && x <= 0) deltaX = 0;
if(deltaY == -1 && y <= 0) deltaY = 0;
x += deltaX;
y += deltaY;
if(deltaX != 0 || deltaY != 0) {
frame.repaint();
}
}
});
t.start();
然后,您的按钮只是通过设置增量值告诉计时器以正确的方向设置动画,例如
class movingup implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
deltaY = -1;
}
}// moving up end
如您所见,我在start
方法中创建了一个计时器对象,并告诉计时器按下按钮开始设置动画。计时器拥有它自己的,不同的ActionListener
(在这里实现为anonymous class)实际上告诉参数改变,然后如果某些东西移动则重新绘制。您可以通过告诉Swing仅重绘需要使用JComponent.repaint(Rectangle)
重绘的屏幕部分来进一步优化它,但这只是一个示例。如果您这样做,请确保重绘足够大,以便 <圈> ,以及现在的位置。
这是完整的程序,包括常量CIRCLE_WIDTH
和CIRCLE_HEIGHT
,新的计时器逻辑,以及所有四个按钮都已更改:
package swingWork;
import java.awt.BorderLayout;
import java.awt.Button;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.*;
public class movingball {
private static final int CIRCLE_WIDTH = 100;
private static final int CIRCLE_HEIGHT = 100;
private static final int TIMER_DELAY = 50;
JFrame frame;
int x = 0;
int y = 0;
int deltaX = 0;
int deltaY = 0;
Timer t;
public static void main(String[] args) {
movingball ball = new movingball();
ball.start();
}
public void start() {
ballDrawer drawer = new ballDrawer();
frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton up = new JButton("UP");
JButton down = new JButton("DOWN");
JButton left = new JButton("LEFT");
JButton right = new JButton("RIGHT");
frame.getContentPane().add(BorderLayout.NORTH, up);
frame.getContentPane().add(BorderLayout.SOUTH, down);
frame.getContentPane().add(BorderLayout.WEST, left);
frame.getContentPane().add(BorderLayout.EAST, right);
frame.getContentPane().add(BorderLayout.CENTER, drawer);
// setting up the action listener:
up.addActionListener(new movingup());
down.addActionListener(new movingdown());
left.addActionListener(new movingleft());
right.addActionListener(new movingright());
frame.setSize(300, 300);
frame.setVisible(true);
t = new Timer(TIMER_DELAY, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
if(deltaX == 1 && x == frame.getWidth() - CIRCLE_WIDTH) deltaX = 0;
if(deltaY == 1 && y == frame.getHeight() - CIRCLE_HEIGHT) deltaY = 0;
if(deltaX == -1 && x == 0) deltaX = 0;
if(deltaY == -1 && y == 0) deltaY = 0;
x += deltaX;
y += deltaY;
if(deltaX != 0 || deltaY != 0) {
frame.repaint();
}
}
});
t.start();
}// start method end
// here we have the listeners
class movingup implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
deltaY = -1;
}
}// moving up end
class movingdown implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
deltaY = 1;
}
}// movingdown end
class movingleft implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
deltaX = -1;
}
}// moving left end
class movingright implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
deltaX = 1;
}
}// moving right end
class ballDrawer extends JPanel {
@Override
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.white);
g.fillRect(0, 0, this.getWidth(), this.getHeight());
g.setColor(Color.black);
g.fillOval(x, y, CIRCLE_WIDTH, CIRCLE_HEIGHT);
}// PaintComponents End
}// ball drawer class end
}// main class endreading: http://stackoverflow.com/q/15511282/1768232
答案 1 :(得分:3)
正如已经指出的那样,您正在阻止事件调度线程,这阻止了UI的更新直到您的循环和方法退出
更好的解决方案是使用Swing Timer
,它会在EDT上下文中为ActionListener
生成常规回调,允许您从其中安全地更新UI。有关详细信息,请参阅Concurrency in Swing和How to use Swing Timers
您还应该致电super.paintComponent
,除其他事项外,还会自动填写Graphcis
背景的背景。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class Movingball {
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
Movingball ball = new Movingball();
ball.start();
}
});
}
private BallDrawer drawer;
public void start() {
drawer = new BallDrawer();
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton up = new JButton("UP");
JButton down = new JButton("DOWN");
JButton left = new JButton("LEFT");
JButton right = new JButton("RIGHT");
frame.getContentPane().add(BorderLayout.NORTH, up);
frame.getContentPane().add(BorderLayout.SOUTH, down);
frame.getContentPane().add(BorderLayout.WEST, left);
frame.getContentPane().add(BorderLayout.EAST, right);
frame.getContentPane().add(BorderLayout.CENTER, drawer);
// setting up the action listener:
up.addActionListener(new Movingup());
down.addActionListener(new Movingdown());
left.addActionListener(new Movingleft());
right.addActionListener(new Movingright());
frame.pack();
frame.setVisible(true);
}// start method end
// here we have the listeners
class Movingup implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
drawer.moveUp();
}
}// moving up end
class Movingdown implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
drawer.moveDown();
}
}// movingdown end
class Movingleft implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
drawer.moveLeft();
}
}// moving left end
class Movingright implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
drawer.moveRight();
}
}// moving right end
public static class BallDrawer extends JPanel {
public static final int CIRCLE_WIDTH = 100;
public static final int CIRCLE_HEIGHT = 100;
private int xDelta;
private int yDelta;
private int xPos;
private int yPos;
public BallDrawer() {
Timer timer = new Timer(40, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
xPos += xDelta;
yPos += yDelta;
if (xPos < 0) {
xPos = 0;
xDelta = 0;
} else if (xPos + CIRCLE_WIDTH > getWidth()) {
xPos = getWidth() - CIRCLE_WIDTH;
xDelta = 0;
}
if (yPos < 0) {
yPos = 0;
yDelta = 0;
} else if (yPos + CIRCLE_HEIGHT > getHeight()) {
yPos = getHeight() - CIRCLE_HEIGHT;
yDelta = 0;
}
repaint();
}
});
timer.start();
}
@Override
public Dimension getPreferredSize() {
return new Dimension(400, 400);
}
public void moveLeft() {
xDelta = -1;
}
public void moveRight() {
xDelta = 1;
}
public void moveUp() {
yDelta = -1;
}
public void moveDown() {
yDelta = 1;
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
g.setColor(Color.black);
g.fillOval(xPos, yPos, CIRCLE_WIDTH, CIRCLE_HEIGHT);
}// PaintComponents End
}// ball drawer class end
}// main class end
你还应该将功能与负责实际管理它的类隔离开来,在这个BallDrawer
应该管理球的运动,而不是其他类,这允许它自包含和可重复使用
答案 2 :(得分:-2)
for循环导致了很多延迟。尝试像这样重构你的代码。
edate = date(datetime.today().year, datetime.today().month, datetime.today().day)