为什么线程会冻结我的actionListener实现中的代码? [英] Why does the thread freeze my code in my actionListener implementation?
问题描述
我试图通过点击按钮(上,下,...)使椭圆移动平稳,并且尝试使用线程尝试并捕获类内部的工作,但是当我在此处使用时,它冻结了整个应用程序.
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
正如已经指出的那样,您正在阻止事件分派线程,这将阻止UI更新,直到您的循环和方法退出为止>
更好的解决方案是使用Swing 您还应该将功能隔离于负责实际管理球的类,在这种情况下,您的 I am trying to make an oval move smoothly by taping the buttons (up,down,...)and I try to use threads with the try and catch it's work inside the class but when I use it here it freezes the whole app. Here is my whole code:
As, has already been pointed out, you're blocking the Event Dispatching Thread, which is preventing the UI from been updated until your loop and method exit A better solution is to use a Swing You should also be calling You should also isolate functionality to the class responsible for actually managing it, in this your 这篇关于为什么线程会冻结我的actionListener实现中的代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!Timer
,它在EDT的上下文中生成对ActionListener
的常规回调,从而使您可以从其中安全地更新UI.请参见 Swing中的并发和BallDrawer
应该管理球的运动,而不是其他球,这使球可以独立存在并且可重复使用./p>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
Timer
, which generates regular callbacks to a ActionListener
within the context of the EDT, allowing you to safely update the UI from within it. See Concurrency in Swing and How to use Swing Timers for more detailssuper.paintComponent
, which, amongst other things, will fill the background of the Graphcis
context for your automatically.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
should be managing the movement of the ball, not the other class, this allows it to be self contained and re-usable.