java 画布中的鼠标监听器不起作用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10556369/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 01:33:03  来源:igfitidea点击:

MouseListener in Canvas not working

javaswinganimationcanvasmouselistener

提问by bdr9

I am having a problem with a game that I am trying to make in Java. I am trying to attach a MouseListener to my canvas, however, when I click on the canvas, nothing happens. I think I may be attaching the MouseListener to the wrong thing, but I don't know what to attach it to. I have tried attaching it to the JFrame and the canvas. Here is my code:

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

回答by Andrew Thompson

General tips, in point form:

一般提示,以点形式:

  1. Don't mix AWT (e.g. Canvas) with Swing (e.g. JFrame) components. Instead of the Canvas, use a JPaneland override paintComponent(Graphics)rather than paint(Graphics).
  2. Don't call Thread.sleep(n)on the EDT. Instead use a Swing based Timerto call repaint()
  3. Don't perform long running operations on the paint method, especially starting an infinite loop! Even the creation of the buffer image should only be done in the case the screen size changes. (left as 'TODO' - BNI)
  4. Add the MouseListeneronce in the constructor or an init()method rather than every time paint is called.
  5. Highly recommend all of Nate's numbered list of notes.
  1. 不要将 AWT(例如Canvas)与 Swing(例如JFrame)组件混合在一起。而不是画布,使用 aJPanel和覆盖paintComponent(Graphics)而不是paint(Graphics)
  2. 不要打电话Thread.sleep(n)给 EDT。而是使用基于 Swing 的Timer调用repaint()
  3. 不要对paint方法执行长时间运行的操作,尤其是启动无限循环!甚至缓冲区图像的创建也应该只在屏幕尺寸发生变化的情况下完成。(左为 'TODO' - BNI)
  4. MouseListener在构造函数或init()方法中添加一次,而不是每次调用paint 时。
  5. 强烈推荐 Nate 的所有编号笔记列表。

Try this code, and compare it carefully to the original to see the changes.

试试这个代码,并仔细地将它与原始代码进行比较以查看更改。

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

回答by Matt Hurne

Your paint() method is tying up the Thread that handles the mouse click event, due to the while (!started) loop that never exits. started is never true because the MouseListener's mouseClicked() is never called because the paint() method is waiting for started to be true! If you remove that loop, the while (true) loop will have a similar effect. Any mouse events that happen while paint() is running will be queued until paint() returns.

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

回答by Nate

Use a JComponent instead of a Canvas. You'll want to add the mouse listener to that object. You'll also need to set up the mouse listener in the constructor, not the paint() method.

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

Edit: You're doing to much in the paint() method as @AndrewThompson pointed out.

编辑:正如@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);

    ...
}

Notes about your code:

关于您的代码的注意事项:

  1. Avoid making fields public static. 99.9% of the time this is not necessary, and usually leads to trouble later.
  2. The painting code seems to be unnecessarily using buffers--the testImage is not used at all currently!
  3. I removed the while(true)loop, but noticed you're drawing an image, modifying the image, and then drawing the image again. You can probably do this in one go.
  4. You should be able to avoid using an Imagebuffer altogether since you're creating a new one each time paint()is called, and clearing it at the beginning. Just draw your graphics directly to g.
  5. Avoid doing I/O from within the paint()method. Load your images during construction or in a background thread.
  1. 避免制作字段public static。在 99.9% 的情况下,这不是必需的,通常会在以后导致麻烦。
  2. 绘画代码似乎不必要地使用缓冲区——test目前根本没有使用图像!
  3. 我删除了while(true)循环,但注意到您正在绘制图像,修改图像,然后再次绘制图像。您可能可以一次性完成此操作。
  4. 您应该能够完全避免使用Image缓冲区,因为每次paint()调用时都会创建一个新缓冲区,并在开始时清除它。只需将您的图形直接绘制到g.
  5. 避免在paint()方法内进行 I/O 。在构建过程中或在后台线程中加载您的图像。