代码之家  ›  专栏  ›  技术社区  ›  Nikolay Kuznetsov

JLabel工具提示干扰鼠标定位器

  •  8
  • Nikolay Kuznetsov  · 技术社区  · 12 年前

    我有Java Swing应用程序 ToolTipMouseTest

    关键线是 label.setToolTipText("label" + i); 。一旦被评论掉,点击标签就会产生 2 mousePressed 在控制台中。启用该行后,点击标签将不会产生任何结果。

    这是预期行为还是错误? 我的目标是在不禁用的情况下显示工具提示 MouseListener 停止工作。

    几乎是SSCCE,但没有进口:

    public class ToolTipMouseTest {
    
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new ToolTipMouseTest();
            }
        });
    }
    
    public ToolTipMouseTest() {
        JFrame frame = new JFrame();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
    
        JLayeredPane lpane = new JLayeredPane() {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(600,400);
            }
        };
    
        MouseAdapter1 mouseAdapter1 = new MouseAdapter1();
        lpane.addMouseListener(mouseAdapter1);
    
        frame.add(lpane);
    
        JPanel panel1 = new JPanel();
        panel1.setSize(new Dimension(600, 400));
        panel1.setOpaque(false);
    
        lpane.add(panel1, JLayeredPane.PALETTE_LAYER);
    
        JPanel panel2 = new JPanel();
        for (int i = 0; i < 5; i++) {
            JLabel label = new JLabel("Label " + i);
            panel2.add(label);
            label.setToolTipText("label" + i); //HERE!!
        }
    
        JScrollPane spane = new JScrollPane(panel2) {
            private static final long serialVersionUID = 1L;
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(300, 200);
            }
        };
    
        MouseAdapter2 mouseAdapter2 = new MouseAdapter2();
        spane.addMouseListener(mouseAdapter2);
    
        panel1.add(spane);
    
        frame.pack();
        frame.setVisible(true);
    }
    
    private class MouseAdapter1 extends MouseAdapter {
        @Override
        public void mousePressed (MouseEvent me) {
            System.out.println("1 mousePressed");
        }
    }
    
    private class MouseAdapter2 extends MouseAdapter {
        @Override
        public void mousePressed (MouseEvent me) {
            System.out.println("2 mousePressed");
        }
    }
    }
    
    1 回复  |  直到 12 年前
        1
  •  18
  •   bric3    3 年前

    它正在按预期工作。让我解释一下原因。

    • 当组件没有侦听器时,鼠标事件将被传播。

    • 当任何组件至少有一个 MouseListener 把它放上去——它会的 消耗任何 在组件层次结构中,鼠标进入/退出/单击/按下/释放事件。

      这对任何听众都是一样的,比如 MouseMotionListener 具有 拖动/移动鼠标。

    • 将工具提示添加到零部件时( JLabel 在您的情况下),该组件会自动收到一个新的MouseListener和 鼠标移动 从…起 ToolTipManager 这个 registerComponent 来自的方法 工具提示管理器 类执行此操作(由调用 setToolTipText ) :

      public void registerComponent(JComponent component) {
          component.removeMouseListener(this);
          component.addMouseListener(this);
          component.removeMouseMotionListener(moveBeforeEnterListener);
          component.addMouseMotionListener(moveBeforeEnterListener);
          component.removeKeyListener(accessibilityKeyListener);
          component.addKeyListener(accessibilityKeyListener);
      }
      

    就你而言- 标签类 s正在消耗鼠标事件和鼠标运动事件,因此阻止将事件传播到 JLayeredPane 因为 工具提示管理器 侦听器在设置工具提示时添加了自身( 设置工具提示文本 )在组件上。

    为了解决这个问题,请注册一个将传递事件的侦听器。您可以使用工具提示将该侦听器添加到每个组件,该工具提示应向下传递鼠标事件(例如 J分层窗格 JScrollPane 等)。

    以下是如何做到这一点的一个小例子:

    var destinationComponent = // the JLayeredPane, JScrollPane, etc with mouse listeners
    
    componentWithToolTip.addMouseListener(new MouseAdapter() {
        public void mousePressed(MouseEvent event) {
            destinationComponent.dispatchEvent(
                    SwingUtilities.convertMouseEvent(
                            event.getComponent(), // the component with the tooltip 
                            event,
                            destinationComponent
                    )
            );
        }
    
        // implements other mouse* handlers as required.
    });
    

    在那个设置中 componentWithToolTip 将有两个侦听器,一个来自ToolTipManager,另一个正在传播。什么时候 带工具提示的组件 它的所有侦听器都将被触发,并且传播侦听器将调度到声明的目标组件 destinationComponent 因此 目的地组件 监听器也会接收鼠标事件。