MouseListener 不调用 mouseClicked 方法

Posted

技术标签:

【中文标题】MouseListener 不调用 mouseClicked 方法【英文标题】:MouseListener doesn't call mouseClicked method 【发布时间】:2021-10-30 09:47:21 【问题描述】:

我以为我正确实现了MouseListener,但是当我点击画布时,它没有到达System.out.println("Click registered");这一行

我看过的所有教程都按照我的方式实现了鼠标监听器。

程序编译完成,除了鼠标监听器外,一切正常。

package ttt;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class Frame extends JFrame implements MouseListener

    public static Field field = new Field();
    public static Game game = new Game();
    public static TTTCanvas tttcanvas = new TTTCanvas();
    static final long serialVersionUID = 1l;
    private static final int width = 700;
    private static final int height = 700;
    
    public Frame() 
    
        setLayout(new BorderLayout());
        setResizable(false);
        setBounds(400, 400, width, height);
        setTitle("Tic Tac Toe");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);
        add(tttcanvas);
        addMouseListener(this);
    
    
    public void mouseClicked(MouseEvent e) 
      
        System.out.println("Click registered");
        int x = field.getFieldfromPixel(e.getX());
        int y = field.getFieldfromPixel(e.getY());
        game.updateField(x, y);
    
    
    public void mouseEntered(MouseEvent e)   
    public void mouseExited(MouseEvent e)   
    public void mousePressed(MouseEvent e)   
    public void mouseReleased(MouseEvent e) 

【问题讨论】:

您不应该使用静态变量。这表明设计不正确。 @camickr 我理解静态变量的方式是它们只能有一个实例,例如我在 3 个类中使用字段,但我想在所有 3 个类中使用相同的字段,所以我used static 关于如何做得更好的任何提示? 程序设计太复杂了讨论一下。我不能建议你应该如何修复设计。一般来说,如果一个类需要访问它没有创建的另一个类,那么您需要将它作为参数传递给该类。正如 ControlAltDelete 在下面的评论中提到的,您可能需要阅读 MVC 设计。 【参考方案1】:

将鼠标监听器添加到您的 ttt 画布

package ttt;

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Frame extends JFrame implements MouseListener

    public static Field field = new Field();
    public static Game game = new Game();
    public static TTTCanvas tttcanvas = new TTTCanvas();
    static final long serialVersionUID = 1l;
    private static final int width = 700;
    private static final int height = 700;
    
    public Frame() 
    
        setLayout(new BorderLayout());
        setResizable(false);
        setBounds(400, 400, width, height);
        setTitle("Tic Tac Toe");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);
        add(tttcanvas);
        tttcanvas.addMouseListener(this); //changed here
    
    
    public void mouseClicked(MouseEvent e) 
      
        System.out.println("Click registered");
        int x = field.getFieldfromPixel(e.getX());
        int y = field.getFieldfromPixel(e.getY());
        game.updateField(x, y);
    
    
    public void mouseEntered(MouseEvent e)   
    public void mouseExited(MouseEvent e)   
    public void mousePressed(MouseEvent e)   
    public void mouseReleased(MouseEvent e) 

【讨论】:

@camickr 我知道你是 Swing 一切的源头,但我认为你在这里给出的建议不是很好。 MouseListener 应该在Controller 类(MVC 模式)中。这可能是 TTTCanvas 类,但如果没有更多信息,我们只是不知道......另外,如果 OP 不知道,引入 MVC 是(IMO)更有用的建议 @ControlAltDel 原始代码不起作用的原因是因为已将 MouseListener 添加到 TTTCanvas 类中,正如我在回答中所解释的那样。我试图提出的主要观点是(对我而言)在两个地方将 MouseListener 添加到 TTTCanvas 类是没有意义的。我会发现让两个侦听器分别从不同的类中添加会令人困惑。我不是想介绍 MVC 设计,因为我不太了解它。 @camickr mouselistener 仅在框架类中,不在 tttcanvas 类中 @warriorloewe 发布的代码不完整。这就是为什么你应该总是添加一个minimal reproducible example 这样我们就不需要猜测了。将侦听器添加到框架将起作用。然而,既然它没有,那么这告诉我一个监听器也被添加到其他地方的 TTTCanvas 类中。这会阻止框架接收事件。我在答案中添加了一个快速演示来演示这个概念。根据您单击的位置,您会收到不同的消息。【参考方案2】:

删除后对我来说效果很好:

//add(tttcanvas);

MouseEvent 只分派给单个组件。

您的 TTTCanvas 类还必须有一个 MouseListner,因此它正在接收事件。

不确定您的确切要求是什么,所以我猜您也可以:

    向 TTTCanvas 类添加第二个 MouseListener 或将两个侦听器的逻辑合并到一个侦听器中,或者 从 TTTCanvas 类中移除监听器

一些代码来证明我的答案:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class Frame extends JFrame implements MouseListener

//    public static Field field = new Field();
//    public static Game game = new Game();
//    public static TTTCanvas tttcanvas = new TTTCanvas();
//    static final long serialVersionUID = 1l;
    private static final int width = 700;
    private static final int height = 700;

    public Frame()
    
        setLayout(new BorderLayout());
        setResizable(false);
        setBounds(400, 400, width, height);
        setTitle("Tic Tac Toe");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLocationRelativeTo(null);
        setVisible(true);
        //add(tttcanvas);

        JPanel panel = new JPanel();
        panel.setPreferredSize( new Dimension(700, 400) );
        panel.setBackground(Color.RED);
        panel.addMouseListener( new MouseAdapter()
        
            @Override
            public void mouseClicked(MouseEvent e)
            
                System.out.println("panel listener");
            
        );

        add(panel, BorderLayout.PAGE_START);

        addMouseListener(this);
    

    public void mouseClicked(MouseEvent e)
    
        System.out.println("frame listener");
    

    public void mouseEntered(MouseEvent e) 
    public void mouseExited(MouseEvent e) 
    public void mousePressed(MouseEvent e) 
    public void mouseReleased(MouseEvent e) 

    public static void main(String[] args) throws Exception
    
        java.awt.EventQueue.invokeLater( () -> new Frame() );
    

    如果您单击红色面板,您会看到“面板侦听器”,因为面板接收的是事件而不是框架。 如果单击灰色,您会看到“帧侦听器”,因为尚未将其他组件添加到框架 BorderLayout 的 CENTER,因此该框架接收到 MouseEvent。

【讨论】:

现在它只在 ttt 画布类作品也谢谢你。我认为在框架类中会更有意义

以上是关于MouseListener 不调用 mouseClicked 方法的主要内容,如果未能解决你的问题,请参考以下文章

当在子组件中添加其他 MouseListener 时,父组件的 MouseListener 在子组件中不起作用

使用 acm.graphics 时 mouseListener 的语法是啥

当我把 MouseListener 类变成错误 [关闭]

可编辑 JavaFX ComboBox 上的 MouseListener

如何将 mouseListener 添加到 jscrollbar?

java MouseListener接口