8

JavaSwingアプリケーションを持っています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

意図したとおりに動作しています。その理由を説明させてください。

  • コンポーネントにリスナーがない場合、マウスイベントが伝播されます。

  • コンポーネントに少なくとも1つのMouseListenerセットがある場合、コンポーネント階層の下位に移動することから、マウスのEnter / Exit / Click / Press/Releaseイベントを消費します。

    MouseMotionListenerこれは、マウスをドラッグ/移動した場合など、どのリスナーでも同じです。

  • コンポーネントにツールチップを追加する場合(JLabelこの場合)、コンポーネントは自動的に新しいMouseListenerとからを受け取りMouseMotionListenerます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);
    }
    

あなたの場合JLabel-sはマウスイベントとマウスモーションイベントを消費しており、ツールチップがコンポーネントに設定されているときにリスナーが自分自身を追加したJLayeredPaneため、イベントがコンポーネントに伝播されるのを防ぎます。ToolTipManagersetToolTipText

これを回避するには、イベントを渡すリスナーを登録します。マウスイベントを渡すツールチップを使用して、そのリスナーをすべてのコンポーネントに追加できます(たとえば、、、JLayeredPaneなど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からのリスナーと伝播するリスナーの2つのリスナーがあります。componentWithToolTipすべてのリスナーがトリガーされ、伝播するリスナーが宣言された宛先コンポーネントにディスパッチするときdestinationComponent。リスナーdestinationComponentがマウスイベントも受信できるようにします。

于 2013-02-18T08:51:29.063 に答える