为什么线程会冻结我的actionListener实现中的代码? [英] Why does the thread freeze my code in my actionListener implementation?

查看:87
本文介绍了为什么线程会冻结我的actionListener实现中的代码?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图通过点击按钮(上,下,...)使椭圆移动平稳,并且尝试使用线程尝试并捕获类内部的工作,但是当我在此处使用时,它冻结了整个应用程序.

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 Timer,它在EDT的上下文中生成对ActionListener的常规回调,从而使您可以从其中安全地更新UI.请参见 Swing中的并发

您还应该将功能隔离于负责实际管理球的类,在这种情况下,您的BallDrawer应该管理球的运动,而不是其他球,这使球可以独立存在并且可重复使用./p>

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.

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

Here is my whole code:

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

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 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 details

You should also be calling super.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

You should also isolate functionality to the class responsible for actually managing it, in this your BallDrawer should be managing the movement of the ball, not the other class, this allows it to be self contained and re-usable.

这篇关于为什么线程会冻结我的actionListener实现中的代码?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆