8

我有 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");
    }
}
}
4

1 回答 1

16

它按预期工作。让我解释一下为什么。

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

  • 当任何组件上至少有一MouseListener组时 - 它会消耗任何鼠标进入/退出/单击/按下/释放事件,以免在组件层次结构中下降。

    对于任何监听器都是一样的,例如MouseMotionListener鼠标拖动/移动。

  • 当您向组件添加工具提示时(JLabel在您的情况下),组件会自动接收一个新的 MouseListener 和一个MouseMotionListenerfrom ToolTipManager。类中的registerComponent方法ToolTipManager执行此操作(由 调用setToolTipText):

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

在您的情况下 - JLabels 正在消耗鼠标事件和鼠标运动事件,因此可以防止将事件传播到,JLayeredPane因为当在组件上ToolTipManager设置工具提示()时,侦听器添加了自身setToolTipText

为了解决此问题,请注册一个将向下传递事件的侦听器。您可以使用工具提示将该侦听器添加到每个组件,该工具提示应该向下传递鼠标事件(例如,传递到 a JLayeredPane、 aJScrollPane等)。

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

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中将有 2 个侦听器,一个来自 ToolTipManager,另一个是传播的。当componentWithToolTip它的所有侦听器将被触发时,传播的侦听器将分派到声明的目标组件destinationComponent。这样destinationComponent侦听器也可以接收鼠标事件。

于 2013-02-18T08:51:29.063 回答