【问题标题】:MouseMotionListener in child component disables MouseListener in parent component子组件中的 MouseMotionListener 禁用父组件中的 MouseListener
【发布时间】:2012-08-06 15:14:29
【问题描述】:

我需要帮助来理解 Swing 中的事件传播。我知道每个事件仅由一个组件处理。因此,当我有一个面板 outside 和一些子面板 inside 并且我将 mouseListeners 添加到它们两者时,将调用 inside 之一。这很好,这是预期的行为。

但我不明白以下情况下的行为: inside 注册一个 MouseMotionListener,outside 注册一个 MouseListener。我希望 inside 消耗所有 MouseMotionEvents 和 outside 来接收 MouseEvents,因为在 inside 上没有正常 MouseEvents 的侦听器。但事实并非如此,inside 不知何故消耗了所有 MouseEvents,而不仅仅是 MouseMotionEvents。

以下代码说明了问题:

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

public class EventTest {
public static void main(String... args) {
    SwingUtilities.invokeLater(new Runnable(){
        @Override
        public void run() {
            JComponent inside = new JPanel(); 
            inside.setBackground(Color.red);
            inside.setPreferredSize(new Dimension(200,200));
            MouseMotionListener mm = new MouseMotionListener() {
                @Override
                public void mouseDragged(MouseEvent arg0) {
                    System.err.println("dragged");                      
                }
                @Override
                public void mouseMoved(MouseEvent arg0) {
                    System.err.println("moved");
                }
            };
            // next line disables handling of mouse clicked events in outside 
            inside.addMouseMotionListener(mm); 

            JComponent outside = new JPanel();
            outside.add(inside);
            outside.setPreferredSize(new Dimension(300,300));
            outside.addMouseListener( new MouseAdapter() {
                public void mouseClicked(MouseEvent e) {
                    System.err.println("clicked");
                }
            });

            JFrame frame = new JFrame();
            frame.add(outside);
            frame.pack();
            frame.setVisible(true);
        }
    });
    }
}

我可以通过在inside 上为父组件可能感兴趣的所有事件注册一个侦听器来解决此问题,然后调用 dispatchEvent 将事件转发给父组件。

a) 有人可以指点我一些文档,其中描述了这种行为吗? MouseEvent 的 javadocs 让我觉得我的期望是正确的。所以,我需要一个不同的描述来理解它。

b) 有没有比上述方案更好的解决方案?

谢谢, 凯瑟琳

编辑:目前还不清楚为什么 Swing 会这样。但看起来,让这些东西正常工作的唯一方法是手动转发事件,我会这样做。

【问题讨论】:

标签: java swing events mouse-listeners


【解决方案1】:

a) 通过design,Java 鼠标事件只有在子组件上没有鼠标侦听器时才会“冒泡”。

b) 您可以将事件转发到另一个组件,如here 及以下所示。

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

public class EventTest {

    public static void main(String... args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                final JComponent outside = new JPanel();
                JComponent inside = new JPanel();
                inside.setBackground(Color.red);
                inside.setPreferredSize(new Dimension(200, 200));
                inside.addMouseMotionListener(new MouseAdapter() {

                    @Override
                    public void mouseDragged(MouseEvent e) {
                        System.err.println("dragged");
                    }

                    @Override
                    public void mouseMoved(MouseEvent e) {
                        System.err.println("moved inside");
                        outside.dispatchEvent(e);
                    }
                });

                outside.add(inside);
                outside.setPreferredSize(new Dimension(300, 300));
                outside.addMouseMotionListener(new MouseAdapter() {

                    @Override
                    public void mouseMoved(MouseEvent arg0) {
                        System.err.println("moved outside");
                    }
                });

                JFrame frame = new JFrame();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(outside);
                frame.pack();
                frame.setVisible(true);
            }
        });
    }
}

【讨论】:

    【解决方案2】:

    与trashgod 的回答非常相似——您可以使用MouseAdapter 作为您的运动监听器,并覆盖它以转发您希望由父级处理的任何事件。这应该只会为您的代码添加最少的数量。

            MouseAdapter mm = new MouseAdapter() {
                @Override
                public void mouseDragged(MouseEvent arg0) {
                    System.err.println("dragged");                      
                }
                @Override
                public void mouseMoved(MouseEvent arg0) {
                    System.err.println("moved");
                }
                @Override
                public void mouseClicked(MouseEvent e) {
                    outside.dispatchEvent(e);
                }
            };
            // For forwarding events
            inside.addMouseListener(mm); 
            // For consuming events you care about
            inside.addMouseMotionListener(mm);
    

    我也找不到使用dispatchEvent(e) 方法的任何方法。我认为你被那条路线卡住了。

    【讨论】:

      【解决方案3】:

      这对我有用:

        Ellipse2D mCircle = new Ellipse2D.Double(x,y,size,size);
      
        void PassMouseEvent(MouseEvent e) {
          getParent().dispatchEvent(e);
        }
      
        public void mousePressed(MouseEvent arg0) {
          if(mCircle.contains(arg0.getX(), arg0.getY())) {
            // Do stuff if we click on this object
          } else {
            // Pass to the underlying object to deal with the mouse event
            PassMouseEvent(arg0);
          }
        }
      

      【讨论】:

        猜你喜欢
        • 2014-09-30
        • 2010-12-20
        • 1970-01-01
        • 1970-01-01
        • 2010-11-19
        • 1970-01-01
        • 1970-01-01
        • 2020-06-01
        • 2017-11-15
        相关资源
        最近更新 更多