【问题标题】:MouseListener in Canvas not working画布中的 MouseListener 不起作用
【发布时间】:2012-05-20 08:18:10
【问题描述】:

我在尝试使用 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));
    }
}

【问题讨论】:

  • 感谢所有回答的人。我不明白paint() 和Canvas 的基本概念,即paint() 是如何多次重新执行的。我将尝试将其更改为使用 JPanel 而不是 Canvas。

标签: java swing animation canvas mouselistener


【解决方案1】:

一般提示,点形式:

  1. 不要将 AWT(例如 Canvas)与 Swing(例如 JFrame)组件混合使用。代替画布,使用JPanel 并覆盖paintComponent(Graphics) 而不是paint(Graphics)
  2. 不要在 EDT 上拨打 Thread.sleep(n)。而是使用基于 Swing 的 Timer 来调用 repaint()
  3. 不要对paint方法执行长时间运行的操作,尤其是启动无限循环!甚至缓冲区图像的创建也应该只在屏幕尺寸发生变化的情况下进行。 (左为“待办事项” - BNI)
  4. 在构造函数或init() 方法中添加一次MouseListener,而不是每次调用paint。
  5. 强烈推荐 Nate 的所有笔记编号列表。

试试这个代码,并仔细比较原始代码以查看变化。

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));
    }
}

【讨论】:

    【解决方案2】:

    使用 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。在构建过程中或在后台线程中加载图像。

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 不止于此。它陷入了之前的循环中,直到用户单击动画才结束!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-04-13
      • 2014-01-30
      • 1970-01-01
      • 2011-12-05
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多