I\'m trying to implement pop-up menus in Java JTree. I\'ve sub-classed DefaultTreeCellRenderer (to change node appearance) and DefaultTreeCellEditor (to create Components to
Taken right out of the JTree API
// If you are interested in detecting either double-click events or when a user clicks on a node, regardless of whether or not it was selected, we recommend you do the following:
final JTree tree = ...;
MouseListener ml = new MouseAdapter() {
public void mousePressed(MouseEvent e) {
int selRow = tree.getRowForLocation(e.getX(), e.getY());
TreePath selPath = tree.getPathForLocation(e.getX(), e.getY());
if(selRow != -1) {
if(e.getClickCount() == 1) {
mySingleClick(selRow, selPath);
}
else if(e.getClickCount() == 2) {
myDoubleClick(selRow, selPath);
}
}
}
};
tree.addMouseListener(ml);
Of course you need to modify it a bit for right click instead of left click
The Renderer is only a transient "rubber stamp", so adding an input listener on that wont be particularly helpful. The Editor, as you point out, is only there once you have gestured to edit. So you want to add a listener to the JTree (assuming it isn't implemented as a composite component).
Call addRightClickListener()
to add the right-click context menu listener to your JTree
. Both overrides are for proper cross-platform functionality (Windows
and Linux
differ here).
private void addRightClickListener()
{
MouseListener mouseListener = new MouseAdapter()
{
@Override
public void mousePressed(MouseEvent mouseEvent)
{
handleContextMenu(mouseEvent);
}
@Override
public void mouseReleased(MouseEvent mouseEvent)
{
handleContextMenu(mouseEvent);
}
};
tree.addMouseListener(mouseListener);
}
private void handleContextMenu(MouseEvent mouseEvent)
{
if (mouseEvent.isPopupTrigger())
{
MyContextMenu contextMenu = new MyContextMenu();
contextMenu.show(mouseEvent.getComponent(),
mouseEvent.getX(),
mouseEvent.getY());
}
}
This task is simple to accomplish, the following is all you need:
//create a class which implements the MouseListener interface and
//implement the following in your overridden mouseClicked method
@Override
public void mouseClicked(MouseEvent e) {
if (SwingUtilities.isRightMouseButton(e)) {
int row = tree.getClosestRowForLocation(e.getX(), e.getY());
tree.setSelectionRow(row);
popupMenu.show(e.getComponent(), e.getX(), e.getY());
}
}
You can then add this custom listener to your desired tree(s).
Thanks everyone. I knew something was wrong when I was spending that much effort on implementing a simple popup.
I dismissed this line of thought at first because it felt weird to resort to x- and y- coordinates to find the node I'm looking for, but I guess this is the way to do it.
// add MouseListener to tree
MouseAdapter ma = new MouseAdapter() {
private void myPopupEvent(MouseEvent e) {
int x = e.getX();
int y = e.getY();
JTree tree = (JTree)e.getSource();
TreePath path = tree.getPathForLocation(x, y);
if (path == null)
return;
tree.setSelectionPath(path);
My_Obj obj = (My_Obj)path.getLastPathComponent();
String label = "popup: " + obj.getTreeLabel();
JPopupMenu popup = new JPopupMenu();
popup.add(new JMenuItem(label));
popup.show(tree, x, y);
}
public void mousePressed(MouseEvent e) {
if (e.isPopupTrigger()) myPopupEvent(e);
}
public void mouseReleased(MouseEvent e) {
if (e.isPopupTrigger()) myPopupEvent(e);
}
};
(...)
JTree tree = new JTree();
tree.addMouseListener(ma);
I think you're making things way harder than they need to be.
JTree has several "add_foo_Listener" methods on it. Implement one of those (TreeSelectionListener looks about right), and then you've got the currently selected node.
Implement a MouseListener so that you can detect the right-click event (and add it to the JTree, since JTree's a Component), and then you should have everything you need to post a context-sensitive menu.
Check out this tutorial for more details.