1

是的,这个问题已经发布在 JavaRanch 上,但我不太了解它们。

我有 JDialog,其中添加了 MouseListener,如下所示:

super.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                if (e.getSource() instanceof ConnectionTreeTooltip) {
                    System.out.println("mouse exited!!!!!!!!!!!!!!!!!!=" + e);
                    // hideTooltip();
                }
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                if (e.getSource() instanceof ConnectionTreeTooltip) {
                    System.out.println("mouse entered!!!!!!!!!!!!!!!!!!=" + e);
                    // hideTooltip();
                }
            }
        });

ConnectionTreeTooltip这是jdialog吗?问题是当鼠标进入或退出 JDialog 时,这两种方法都会被调用。他们只是一起跑。

我的 JDialog 的代码:

public class ConnectionTreeTooltip extends JDialog {
...........
public ConnectionTreeTooltip(ConnectionsTree connectionsTree) {
        super(connectionsTree.getMainFrame(), "", false);
        super.setUndecorated(true);
        super.setFocusableWindowState(false);
.............
super.getContentPane().add(scrollPane);
        super.pack();
    }

connectionsTree.getMainFrame()返回 JFrame 的实例。

编辑这是完整的代码:

public ConnectionTreeTooltip(ConnectionsTree connectionsTree) {
        super(connectionsTree.getMainFrame(), "", false);
        super.setUndecorated(true);
        super.setFocusableWindowState(false);

        this.connectionsTree = connectionsTree;
        JPanel contentPane = (JPanel) super.getContentPane();
        contentPane.setBorder(BorderFactory.createEtchedBorder(EtchedBorder.LOWERED, Color.blue, Color.red));
        tipLabel = new JLabel();
        // by default, JLabel is not focusable.
        tipLabel.setFocusable(true);
        tipLabel.setBackground(Color.WHITE);
        scrollPane = new JScrollPane(tipLabel) {
            @Override
            public Dimension getPreferredSize() {
                return preferredSizeOfScrollPane;
            }
        };
        scrollPane.setBorder(BorderFactory.createEmptyBorder(3, 3, 1, 1));
        super.addMouseListener(new MouseAdapter() {
            @Override
            public void mouseExited(MouseEvent e) {
                if (e.getSource() instanceof ConnectionTreeTooltip) {
                    System.out.println("mouse exited!!!!!!!!!!!!!!!!!!=" + e);
                    // hideTooltip();
                }
            }

            @Override
            public void mouseEntered(MouseEvent e) {
                if (e.getSource() instanceof ConnectionTreeTooltip) {
                    System.out.println("mouse entered!!!!!!!!!!!!!!!!!!=" + e);
                    // hideTooltip();
                }
            }
        });
        tipLabel.addKeyListener(new KeyAdapter() {
            @Override
            public void keyReleased(KeyEvent e) {
                // tipLabel can key events only if it is visible and focused
                if (e.getKeyCode() == 32) {
                    unFocusTipLabel();
                }
            }
        });
        super.getContentPane().add(scrollPane);
        super.pack();
    }

为什么会这样,我的 JDialog 或 MouseListener 有什么问题?

谢谢!

4

3 回答 3

2

您的 JDialog 很可能在其中包含一个组件,该组件从对话框本身窃取鼠标侦听器,因此当您的鼠标进入对话框时,对话框会感应到鼠标进入,但随后鼠标立即进入对话框的组件(可能是 JScrollPane ),mouselistener 会感知到您已经离开对话框并进入了它的子组件。

例如,我的 SSCCE:

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

public class MouseListenerTest {
   public static void main(String[] args) {
      final JFrame mainFrame = new JFrame("My Frame");
      mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      mainFrame.add(new JPanel() {
         {
            add(new JButton(new AbstractAction("Show Dialog") {

               @Override
               public void actionPerformed(ActionEvent arg0) {
                  ConnectionTreeTooltip cttt = new ConnectionTreeTooltip(
                        mainFrame);
                  cttt.setVisible(true);
               }
            }));
         }
      });
      mainFrame.pack();
      mainFrame.setLocationRelativeTo(null);
      mainFrame.setVisible(true);

   }
}

class ConnectionTreeTooltip extends JDialog {

   public ConnectionTreeTooltip(JFrame mainFrame) {
      super(mainFrame, "", false);
      setUndecorated(true);
      setFocusableWindowState(false);
      add(new JScrollPane(new JTextArea(20, 40)));
      ((JPanel)getContentPane()).setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
      pack();
      addMouseListener(new MouseAdapter() {
         @Override
         public void mouseExited(MouseEvent e) {
            if (e.getSource() instanceof ConnectionTreeTooltip) {
               System.out.println("mouse exited!!!!!!!!!!!!!!!!!!=" + e);
               // hideTooltip();
            }
         }

         @Override
         public void mouseEntered(MouseEvent e) {
            if (e.getSource() instanceof ConnectionTreeTooltip) {
               System.out.println("mouse entered!!!!!!!!!!!!!!!!!!=" + e);
               // hideTooltip();
            }
         }
      });
   }
}

现在最困难的部分是弄清楚如何使用 GlassPane 来获取鼠标进入/离开信息,但仍然允许将鼠标事件传递到玻璃窗格下方的对话框中。


编辑

是的,解决方案是使用玻璃窗格:

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

public class MouseListenerTest {
   public static void main(String[] args) {
      final JFrame mainFrame = new JFrame("My Frame");
      mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

      mainFrame.add(new JPanel() {
         {
            add(new JButton(new AbstractAction("Show Dialog") {

               @Override
               public void actionPerformed(ActionEvent arg0) {
                  ConnectionTreeTooltip cttt = new ConnectionTreeTooltip(
                        mainFrame);
                  cttt.setVisible(true);
               }
            }));
         }
      });
      mainFrame.pack();
      mainFrame.setLocationRelativeTo(null);
      mainFrame.setVisible(true);

   }
}

class ConnectionTreeTooltip extends JDialog {

   public ConnectionTreeTooltip(JFrame mainFrame) {
      super(mainFrame, "", false);
      setUndecorated(true);
      setFocusableWindowState(false);
      add(new JScrollPane(new JTextArea(20, 40)));
      ((JPanel) getContentPane()).setBorder(
            BorderFactory.createEmptyBorder(4, 4, 4, 4));
      pack();

      JComponent glassPane = (JComponent) getGlassPane();
      glassPane.setVisible(true);

      glassPane.addMouseListener(new MyMouseAdapter());
   }

   private class MyMouseAdapter extends MouseAdapter {

      @Override
      public void mouseExited(MouseEvent e) {
         System.out.println("mouse exited");
      }

      @Override
      public void mouseEntered(MouseEvent e) {
         System.out.println("mouse entered");
      }
   }
}
于 2013-09-05T19:19:11.370 回答
1

我以比使用 GlassPane 更好的方式解决了我的问题。GlassPane 只会给我增加更多麻烦,因为我无法滚动 GlassPane 下的 JScrollPane,并且 glasspane swing 教程中建议的重新分配鼠标事件根本没有帮助,因为 glasspane 上的 mouseListener 没有收到 mouseDragged。

解决方案是使用 AWTEventListener。使用 AWTEventListener 我可以检查组件事件是否开启以及事件的 ID。因此,我的 AWTEventListener 检查 mouseEntered 事件是否发生在 JDialog 上,如果是,则以编程方式聚焦。如果 mouseDragged 事件发生在 JScrollPane 上,我会以编程方式滚动它。最后,如果在 JDialog 上发生 mouseExited 事件,它会被隐藏。

Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
            @Override
            public void eventDispatched(AWTEvent event) {
                MouseEvent me = (MouseEvent) event;
                Component mouseComponent = me.getComponent();
                if (mouseComponent == scrollPane) {
                    if (me.getID() == MouseEvent.MOUSE_DRAGGED) {
                         scrollPane.getViewport().setViewPosition(me.getPoint());  // scroll JScrollPane programmatically
                    }
                } else if (mouseComponent == ConnectionTreeTooltip.this) {
                    if (me.getID() == MouseEvent.MOUSE_ENTERED)
                        focusTipLabel(); //focus JDialog(ConnectionTreeTooltip)
                    else if (me.getID() == MouseEvent.MOUSE_EXITED) {
                        hideTooltip(); //hide JDialog(ConnectionTreeTooltip)
                    }
                }
            }
        }, AWTEvent.MOUSE_EVENT_MASK);

但是这个 AWTEventListener 适用于从我的主框架中的任何组件生成的鼠标事件。而且它并不总是处理 JDialog 上的 mouseExited 事件。

于 2013-09-14T08:45:31.303 回答
0

或者更简单的选择。检查鼠标在 mouseExited 上的坐标,如果鼠标确实在控件之外,则仅计为退出:

super.addMouseListener(new MouseAdapter() {
    @Override
    public void mouseExited(MouseEvent e) {

        Point cursor = e.getPoint();
        if ( (cursor.x < super.getX()) || (cursor.y < super.getY()) || (cursor.x > popup.getX()+super.getWidth()) || (cursor.y > super.getY()+super.getHeight()))
            popup.setVisible(false);
    }
});
于 2014-05-14T18:48:53.100 回答