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 的语法是啥
可编辑 JavaFX ComboBox 上的 MouseListener