2013-05-17 22:14:36Morris

[JAVA][作業] 練習線程



設計一個可以鍵盤監聽、滑鼠監聽。
只要有動作,就將可以自由碰撞的按鈕增加一個。

這作業有一個討論的問題:
Race condition (競態條件)
也就是因為有很多線程,再處理的時候會爭奪資源,誰先誰後就變得很重要。
因此有可能會發生無法接受鍵盤監聽與滑鼠監聽,基本上感覺起來就是相當不靈敏。

最後使用 Timer.class 去解決,我想很重要原因是 Thread.sleep() 會導致整個 class 暫停?


同時也會發現,Java 有很多觸發事件,但很多觸發事件都是單線程的,
即不會在一個觸發事件處理中時,同時再次觸發,後者會被撞擊掉(忽略)。




package ce1002.E6.s100502205;

import java.awt.Graphics;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;

import javax.swing.JFrame;
import javax.swing.JButton;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import java.util.Vector;
import java.util.Timer;
import java.util.TimerTask;

public class E6 extends JFrame implements KeyEventDispatcher {
    public final int btnWidth = 50;
    public final int btnHeight = 50;
    public final int Width = 450;
    public final int Height = 450;
    boolean runable = false, addIng = false;
    int totButton = 0;
    public static Vector<MovingButton> buttonList;

    public E6() {
        this.setTitle("E6");
        this.setSize(Width, Height);
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        this.setResizable(false);
        this.setLayout(null);
        this.buttonList = new Vector<MovingButton>();
        addDouble();
        this.setVisible(true);
        Timer timer = new Timer();
        timer.schedule(new Process(), 100, 30);
        KeyboardFocusManager.getCurrentKeyboardFocusManager()
                .addKeyEventDispatcher(this);
    }

    class Process extends TimerTask {
        public void run() {
            if (!addIng) {
                for (MovingButton bb : buttonList)
                    bb.adjust();
                repaint();
            } else {
            }
        }
    }

    public boolean dispatchKeyEvent(KeyEvent e) {
        if (e.getID() == KeyEvent.KEY_RELEASED)
            return false;
        addDouble();
        return false;
    }

    public void addDouble() {
        addIng = true;
        MovingButton tmp = new MovingButton(this.getWidth() / 2,
                this.getHeight() / 2, btnWidth, btnHeight, this);
        buttonList.add(tmp);
        this.add(tmp);
        addIng = false;
    }

    class MovingButton extends JButton {
        double x, y;
        double vx, vy;
        int count = 0;
        E6 parent;

        public MovingButton(int x, int y, int width, int height, E6 parent) {
            super();
            totButton++;
            this.setBounds(x, y, width, height);
            this.x = x;
            this.y = y;
            this.parent = parent;
            this.setText("0");
            double theta = Math.random() * 2 * Math.PI;
            vx = Math.sin(theta) * 5;
            vy = Math.cos(theta) * 5;
            this.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    double theta = Math.random() * 2 * Math.PI;
                    vx = Math.sin(theta) * 5;
                    vy = Math.cos(theta) * 5;
                    addDouble();
                }
            });
            this.addMouseListener(new MouseListener() {
                @Override
                public void mouseClicked(MouseEvent e) {
                    addDouble();
                }

                @Override
                public void mouseEntered(MouseEvent arg0) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void mouseExited(MouseEvent arg0) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void mousePressed(MouseEvent arg0) {
                    // TODO Auto-generated method stub

                }

                @Override
                public void mouseReleased(MouseEvent arg0) {
                    // TODO Auto-generated method stub

                }
            });
        }

        void addDouble() {
            parent.addDouble();
        }

        void adjust() {
            boolean crash = false;
            if (x + vx < 0 || x + vx + this.getWidth() + 20 >= Width) {
                vx = -vx;
                crash = true;
            }
            if (y + vy < 0 || y + vy + this.getHeight() + 20 >= Height) {
                vy = -vy;
                crash = true;
            }
            x += vx;
            y += vy;
            if (crash == true) {
                count++;
                this.setText("" + count);
            }
            this.setBounds((int) x, (int) y, this.getWidth(), this.getHeight());
        }
    }

    public static void main(String[] args) {
        new E6();
    }
}