Search code examples
javaswingmouseeventjtreemouselistener

Using MouseListener with JTree


I am using a MouseListener to detect double clicks on JTree items. That JTree is located in a JScrollPane. When I detect a double click (a MouseEvent), I get the path for the click location from the JTree. Most of the time, this works fine.

Now if I double click on a (collapsed) node with children, the node expands and therefor the scroll pane scrolls down. When I try to get the tree path from the click location, the JTree looks at the current (scrolled) view and returns the wrong item as the click location refers to the previous view (not scrolled).

Does anyone have an idea how to fix this? Below, I will attach an example demonstrating the problem.


package test;

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import javax.swing.JDialog;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreePath;

public class TestMain extends JDialog implements MouseListener {

    protected final JTree tree;

    public TestMain() {
        tree = new JTree(getRootNode());
        tree.addMouseListener(this);

        JScrollPane pane = new JScrollPane(tree);
        pane.setPreferredSize(new Dimension(250, 300));

        getContentPane().add(pane, BorderLayout.CENTER);
        pack();
    }

    private TreeNode getRootNode() {
        DefaultMutableTreeNode root = new DefaultMutableTreeNode("Root");

        for (int i = 0; i < 10; i++) {
            root.add(new DefaultMutableTreeNode("Node " + i));
        }

        DefaultMutableTreeNode sub = new DefaultMutableTreeNode("Sub");
        root.add(sub);

        for (int i = 0; i < 10; i++) {
            sub.add(new DefaultMutableTreeNode("Sub " + i));
        }

        return root;
    }

    @Override
    public void mouseClicked(MouseEvent e) {
        if (e.getClickCount() == 2) {
            TreePath path = tree.getPathForLocation(e.getX(), e.getY());
            if (path != null) {
                System.out.println(path.getLastPathComponent().toString());
            }
        }
    }

    @Override
    public void mousePressed(MouseEvent e) {

    }

    @Override
    public void mouseReleased(MouseEvent e) {

    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }

    public static void main(String[] args) {
        JDialog dialog = new TestMain();
        dialog.setVisible(true);
    }
}

Solution

  • I would recommend you to use JTree.getSelectionPath().getLastPathComponent() since it won't change on scroll.