Canvas中的MouseListener无法正常工作

时间:2012-05-11 18:01:26

标签: java swing animation canvas mouselistener

我正在尝试使用Java制作游戏。我试图将MouseListener附加到我的画布,但是,当我点击画布时,没有任何反应。我想我可能会将MouseListener附加到错误的东西,但我不知道要将它附加到什么。我已经尝试将它附加到JFrame和画布上。这是我的代码:

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;

import java.io.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import java.util.Random;

public class Gravity extends Canvas {

    public static final int screenw = 1024;
    public static final int screenh = 768;

    public static Random gen = new Random();

    public static Boolean started = false;

    public static int[] starx = new int[100];
    public static int[] stary = new int[100];
    public static Color[] starc = new Color[100];

    public static JFrame frame;
    public static Gravity canvas;
    public static Image buffer;
    public static Graphics bg;

    public static int[] xh = new int[1000];
    public static int[] yh = new int[1000];

    public static int i = 0;

    public static Image title;

    public static ArrayList<Integer> ptx = new ArrayList<Integer>();
    public static ArrayList<Integer> pty = new ArrayList<Integer>();
    double x = 100;
    double y = 100;

    public Gravity(){
    }

    public void paint (Graphics g) {
        frame.addMouseListener(new MouseListener(){
            public void mouseClicked(MouseEvent e){
                started = true;
                System.out.println("Mouse was clicked");
            }

            public void mouseEntered(MouseEvent arg0) {}
            public void mouseExited(MouseEvent arg0) {}
            public void mousePressed(MouseEvent arg0) {}
            public void mouseReleased(MouseEvent arg0) {}
        });


        buffer = createImage(screenw, screenh);
        bg = buffer.getGraphics();

        int w = getWidth();
        int h = getHeight();

        double px = getWidth()/2; 
        double py = getHeight()/2;

        bg.setColor(Color.BLACK);
        bg.fillRect(0, 0, w, h); //black background

        for (int j=0; j < 100; j++){ //make stars
            starx[j] = gen.nextInt(w);
            stary[j] = gen.nextInt(h);
            starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156);
            bg.setColor(starc[j]);
            bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2);
            bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]);
        }

        try {
            title = ImageIO.read(new ByteArrayInputStream(Base64.decode(""))); //I have omitted the Base64 code for the image for my title screen
        } catch (IOException e) {
            e.printStackTrace();
        }

        bg.drawImage(title, 100, 100, null);
        g.drawImage(buffer, 0, 0, null);

        while (!started){
            try {
                Thread.sleep(50);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
        }

        double xvel = -15;
        double yvel = 10;

        for (int j=0; j < 100; j++){ //store stars
            starx[j] = gen.nextInt(w);
            stary[j] = gen.nextInt(h);
            starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156);
        }

        Image test = createImage(200,200);
        Graphics testg = test.getGraphics();
        testg.drawLine(50,50,150,150);

        while(true){
            g.drawImage(buffer, 0,0, null);
            try {
                Thread.sleep(33);
            } catch (Exception e) {
                e.printStackTrace();
            }

            bg.setColor(Color.BLACK);
            bg.fillRect(0, 0, w, h); //black background


            for (int j=0; j < 100; j++){ //draw stars
                bg.setColor(starc[j]);
                bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2);
                bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]);
            }

            bg.setColor(Color.BLUE);

            if (i > 0){
                for (int z=0; z < i-1; z++){
                    bg.drawLine(ptx.get(z), pty.get(z), ptx.get(z+1), pty.get(z+1));
                }
            }

            bg.setColor(Color.CYAN);
            bg.fillOval((int)px, (int)py, 25, 25); //planet

            bg.setColor(Color.RED);
            bg.fillRect((int)(x-5),(int)(y-5),10,10); //ship

            double fg = (5*50000)/(Math.pow(dist(x,y,px,py),2));

            double m = (y-py)/(x-px);
            double ms = Math.sqrt(Math.abs(m));
            if (m < 0) ms = -ms;

            double xchg = fg;
            double ychg = fg*ms;

            if (x > px){
                xchg = -xchg;
                ychg = -ychg;
            }

            xvel += xchg;
            yvel += ychg;

            x += xvel;
            y += yvel;

            ptx.add((int)x);
            pty.add((int)y);

            i++;
        }
    }

    public static void main(String[] args){

        canvas = new Gravity();
        frame = new JFrame();
        frame.setSize(screenw, screenh);
        frame.setResizable(false);
        frame.setLocationRelativeTo(null);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.getContentPane().add(canvas);

        frame.setVisible(true);
    }


    public static double dist(double x1, double y1, double x2, double y2){
        double x = x2-x1;
        double y = y2-y1;
        return Math.sqrt((x*x)+(y*y));
    }
}

3 个答案:

答案 0 :(得分:3)

一般提示,以点形式:

  1. 请勿将AWT(例如Canvas)与Swing(例如JFrame)组件混合使用。而不是使用Canvas,使用JPanel并覆盖paintComponent(Graphics)而不是paint(Graphics)
  2. 请勿在EDT上致电Thread.sleep(n)。而是使用基于Swing的Timer来调用repaint()
  3. 不要对paint方法执行长时间运行操作,尤其是启动无限循环!甚至只有在屏幕尺寸改变的情​​况下才能创建缓冲图像。 (左为'TODO' - BNI)
  4. 在构造函数或MouseListener方法中添加init()一次,而不是每次调用paint。
  5. 强烈推荐Nate编号的所有笔记。
  6. 尝试使用此代码,并仔细比较原始代码以查看更改。

    import java.awt.Color;
    import java.awt.Graphics;
    import java.awt.Image;
    import java.awt.Dimension;
    import java.awt.event.*;
    import java.util.ArrayList;
    
    import java.io.*;
    
    import javax.imageio.ImageIO;
    import javax.swing.*;
    import java.util.Random;
    
    public class Gravity extends JPanel {
    
        public static final int screenw = 800;
        public static final int screenh = 600;
    
        public static Random gen = new Random();
    
        public static int[] starx = new int[100];
        public static int[] stary = new int[100];
        public static Color[] starc = new Color[100];
    
        public static Image buffer;
        public static Graphics bg;
    
        public static int[] xh = new int[1000];
        public static int[] yh = new int[1000];
    
        public static int i = 0;
    
        public static ArrayList<Integer> ptx = new ArrayList<Integer>();
        public static ArrayList<Integer> pty = new ArrayList<Integer>();
        double x = 100;
        double y = 100;
    
        Timer timer;
    
        public Gravity(){
            // set thre PREFERRED size!
            setPreferredSize(new Dimension(screenw, screenh));
            addMouseListener(new MouseListener(){
                        public void mouseClicked(MouseEvent e){
                            System.out.println("Mouse was clicked");
                            timer.start();
                        }
    
                        public void mouseEntered(MouseEvent arg0) {}
                        public void mouseExited(MouseEvent arg0) {}
                        public void mousePressed(MouseEvent arg0) {}
                        public void mouseReleased(MouseEvent arg0) {}
            });
            ActionListener animation = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    repaint();
                }
            };
            timer = new Timer(50, animation);
        }
    
        @Override
        public void paintComponent(Graphics g) {
            buffer = createImage(screenw, screenh);
            bg = buffer.getGraphics();
    
            int w = getWidth();
            int h = getHeight();
    
            double px = getWidth()/2;
            double py = getHeight()/2;
    
            bg.setColor(Color.BLACK);
            bg.fillRect(0, 0, w, h); //black background
    
            for (int j=0; j < 100; j++){ //make stars
                starx[j] = gen.nextInt(w);
                stary[j] = gen.nextInt(h);
                starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156);
                bg.setColor(starc[j]);
                bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2);
                bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]);
            }
    
            g.drawImage(buffer, 0, 0, null);
    
            double xvel = -15;
            double yvel = 10;
    
            for (int j=0; j < 100; j++){ //store stars
                starx[j] = gen.nextInt(w);
                stary[j] = gen.nextInt(h);
                starc[j] = new Color(gen.nextInt(100)+156, gen.nextInt(100)+156, gen.nextInt(100)+156);
            }
    
            Image test = createImage(200,200);
            Graphics testg = test.getGraphics();
            testg.drawLine(50,50,150,150);
    
            g.drawImage(buffer, 0,0, null);
            try {
                Thread.sleep(33);
            } catch (Exception e) {
                e.printStackTrace();
            }
    
            bg.setColor(Color.BLACK);
            bg.fillRect(0, 0, w, h); //black background
    
    
            for (int j=0; j < 100; j++){ //draw stars
                bg.setColor(starc[j]);
                bg.drawLine(starx[j], stary[j], starx[j]+2, stary[j]+2);
                bg.drawLine(starx[j], stary[j]+2, starx[j]+2, stary[j]);
            }
    
            bg.setColor(Color.BLUE);
    
            if (i > 0){
                for (int z=0; z < i-1; z++){
                    bg.drawLine(ptx.get(z), pty.get(z), ptx.get(z+1), pty.get(z+1));
                }
            }
    
            bg.setColor(Color.CYAN);
            bg.fillOval((int)px, (int)py, 25, 25); //planet
    
            bg.setColor(Color.RED);
            bg.fillRect((int)(x-5),(int)(y-5),10,10); //ship
    
            double fg = (5*50000)/(Math.pow(dist(x,y,px,py),2));
    
            double m = (y-py)/(x-px);
            double ms = Math.sqrt(Math.abs(m));
            if (m < 0) ms = -ms;
    
            double xchg = fg;
            double ychg = fg*ms;
    
            if (x > px){
                xchg = -xchg;
                ychg = -ychg;
            }
    
            xvel += xchg;
            yvel += ychg;
    
            x += xvel;
            y += yvel;
    
            ptx.add((int)x);
            pty.add((int)y);
    
            i++;
        }
    
        public static void main(String[] args){
            SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    JFrame frame = new JFrame();
    
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.getContentPane().add(new Gravity());
                    frame.setResizable(false);
                    frame.pack();
    
                    frame.setLocationByPlatform(true);
                    frame.setVisible(true);
                }
            });
        }
    
    
        public static double dist(double x1, double y1, double x2, double y2){
            double x = x2-x1;
            double y = y2-y1;
            return Math.sqrt((x*x)+(y*y));
        }
    }
    

答案 1 :(得分:1)

你的paint()方法正在占用处理鼠标点击事件的线程,因为while(!started)循环永不退出。 start永远不会是真的,因为从不调用MouseListener的mouseClicked()因为paint()方法等待开始为真!如果删除该循环,while(true)循环将具有类似的效果。在paint()运行时发生的任何鼠标事件都将排队,直到paint()返回。

答案 2 :(得分:1)

使用JComponent而不是Canvas。您需要将鼠标侦听器添加到该对象。您还需要在构造函数中设置鼠标侦听器,而不是paint()方法。

编辑:正如@AndrewThompson指出的那样,你在paint()方法中做了很多工作。

public Gravity() {
    addMouseListener(new MouseListener() {

        @Override
        public void mouseClicked(MouseEvent e) {
            System.out.println("Mouse was clicked");
        }

        @Override
        public void mouseEntered(MouseEvent arg0) {
        }

        @Override
        public void mouseExited(MouseEvent arg0) {
        }

        @Override
        public void mousePressed(MouseEvent arg0) {
        }

        @Override
        public void mouseReleased(MouseEvent arg0) {
        }
    });
}

@Override
public void paint(Graphics g) {

    buffer = createImage(screenw, screenh);
    bg = buffer.getGraphics();

    ...

    bg.setColor(Color.BLACK);
    bg.fillRect(0, 0, w, h); // black background

    for (int j = 0; j < 100; j++) { // make stars
        ...
    }

    bg.drawImage(title, 100, 100, null);
    g.drawImage(buffer, 0, 0, null);

    double xvel = -15;
    double yvel = 10;

    for (int j = 0; j < 100; j++) { // store stars
        ...
    }

    Image test = createImage(200, 200);
    Graphics testg = test.getGraphics();
    testg.drawLine(50, 50, 150, 150);

    g.drawImage(buffer, 0, 0, null);
    bg.setColor(Color.BLACK);
    bg.fillRect(0, 0, w, h); // black background

    for (int j = 0; j < 100; j++) { // draw stars
        ...
    }

    bg.setColor(Color.BLUE);

    if (i > 0) {
        for (int z = 0; z < i - 1; z++) {
            bg.drawLine(ptx.get(z), pty.get(z), ptx.get(z + 1), pty.get(z + 1));
        }
    }

    bg.setColor(Color.CYAN);
    bg.fillOval((int) px, (int) py, 25, 25); // planet

    bg.setColor(Color.RED);
    bg.fillRect((int) (x - 5), (int) (y - 5), 10, 10); // ship

    ....

    ptx.add((int) x);
    pty.add((int) y);
}

public static void main(String[] args) {
    ...

    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);

    ...
}

关于您的代码的说明:

  1. 避免使用字段public static。 99.9%的时间没有必要,通常会在以后导致麻烦。
  2. 绘画代码似乎不必要地使用缓冲区 - 目前还没有使用test图像!
  3. 我删除了while(true)循环,但注意到您正在绘制图像,修改图像,然后再次绘制图像。你可以一次性做到这一点。
  4. 您应该能够完全避免使用Image缓冲区,因为每次调用paint()时都会创建一个新缓冲区,并在开头清除它。只需将图形直接绘制到g
  5. 避免在paint()方法中进行I / O操作。在构造期间或后台线程中加载图像。