检测鼠标悬停图标

Detect mouseover icon

我可以使用下面的代码检测鼠标何时位于我的 JTree 的文本部分上。我还想检测用户何时将鼠标悬停在用于 expand/collapse 事物的 JTree 文本左侧的图标上,并相应地更改光标。我该怎么做?

import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreePath;

public class Testing {

    public static void main(String[] args) throws Exception {
        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        JTree tree = new JTree(buildTree());
        tree.addMouseMotionListener(new MouseMotionListener() {

            @Override
            public void mouseDragged(MouseEvent e) {
            }

            @Override
            public void mouseMoved(MouseEvent e) {
                TreePath tp = ((JTree) e.getSource()).getPathForLocation(e.getX(), e.getY());
                if (tp != null) {
                    ((JTree) e.getSource()).setCursor(new Cursor(Cursor.HAND_CURSOR));
                } else {
                    ((JTree) e.getSource()).setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                }
            }
        });
        frame.add(panel);
        panel.add(tree);
        frame.setSize(new Dimension(200, 200));
        frame.setVisible(true);
    }

    public static DefaultMutableTreeNode buildTree() {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");
        DefaultMutableTreeNode subOne = new DefaultMutableTreeNode("Test1");
        DefaultMutableTreeNode leafOne = new DefaultMutableTreeNode("Leaf");
        DefaultMutableTreeNode subTwo = new DefaultMutableTreeNode("Test2");
        subOne.add(leafOne); //Drop down button should detect hover over
        root.add(subOne);
        root.add(subTwo);
        return root;
    }
}

这是我为您提供的解决方案。我们需要反射来检查鼠标是否在图标上,因为所需的方法被声明为受保护的。

import java.awt.Cursor;
import java.awt.event.MouseEvent;
import java.awt.event.MouseMotionListener;
import java.lang.reflect.Method;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.SwingUtilities;
import javax.swing.WindowConstants;
import javax.swing.plaf.basic.BasicTreeUI;
import javax.swing.tree.TreePath;


public class TreeTest implements Runnable {

    @Override
    public void run() {
        JTree tree = new JTree();
        tree.addMouseMotionListener(new MouseMotionListener() {

            @Override
            public void mouseDragged(MouseEvent e) {
            }

            @Override
            public void mouseMoved(MouseEvent e) {
                JTree t = (JTree) e.getSource();
                TreePath tp = t.getPathForLocation(e.getX(), e.getY());
                if (tp != null) {
                    t.setCursor(new Cursor(Cursor.HAND_CURSOR));
                } else {
                    boolean overIcon = false;
                    tp = t.getClosestPathForLocation(e.getX(), e.getY());
                    if (tp != null && t.getUI() instanceof BasicTreeUI) {
                        BasicTreeUI ui = (BasicTreeUI) tree.getUI();
                        if (isInExpandControl(ui, tp, e)) {
                            overIcon = true;
                            t.setCursor(new Cursor(Cursor.MOVE_CURSOR)); // set another cursor
                        }
                    }
                    if (!overIcon) {
                        t.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
                    }
                }
            }
        });
        JFrame frm = new JFrame("Tree test");
        frm.add(new JScrollPane(tree));
        frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        frm.pack();
        frm.setLocationRelativeTo(null);
        frm.setVisible(true);
    }

    private boolean isInExpandControl(BasicTreeUI ui, TreePath tp, MouseEvent evt) {
        try {
            Method m = BasicTreeUI.class.getDeclaredMethod("isLocationInExpandControl", TreePath.class, int.class, int.class);
            m.setAccessible(true);
            return Boolean.TRUE.equals(m.invoke(ui, tp, evt.getX(), evt.getY()));
        } catch (Exception e) {
            return false;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new TreeTest());
    }
}