4

I have a situation where I have a popup menu created when a JTable is right clicked on. Standard way of creating the popup menu:

aJTable.setComponentPopupMenu(rightClickMenu);

Now afterwards in the action that gets registered, I am unable to find out which cell was right clicked on to get that popup menu to appear.

rightClickMenuItem.addActionListener(new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        // Work out what cell was right clicked to generate the menu
    }

});

Any ideas on how you do this?

Andrew Thompson
  • 168,117
  • 40
  • 217
  • 433
Ramo
  • 283
  • 1
  • 5
  • 15
  • in listener for right click save the value of cell clicked – Nikolay Kuznetsov Dec 11 '12 at 06:34
  • @NikolayKuznetsovThere's no Mouselistener there, since it was added using the setComponentPopupMenu method - which I'm told is the proper way to do right click menus – Ramo Dec 11 '12 at 06:39
  • 2
    @NikolayKuznetsov By the time that `actionPerformed` method for the `rightClickMenuItem` is triggered, the menu has already been shown. The popupmenu is actually been triggered by the table it-self – MadProgrammer Dec 11 '12 at 06:39
  • 1
    You could inspect the popup itself, but that's messy and unreliable. I believe the preferred solution to this problem is to extend a custom table and override the [`JComponent#getPopupLocation`](http://docs.oracle.com/javase/7/docs/api/javax/swing/JComponent.html#getPopupLocation%28java.awt.event.MouseEvent%29) method – MadProgrammer Dec 11 '12 at 06:41
  • @MadProgrammer, I understand now, thanks. I also believe it has something to do with `getPopupLocation()`, i.e. getting indexes of cell from that method. – Nikolay Kuznetsov Dec 11 '12 at 06:45
  • *"Cheers Ramo"* Don't waste 4 lines of screen space on salutations. – Andrew Thompson Dec 11 '12 at 06:49

3 Answers3

5

Astonishing fact: with a componentPopupMenu installed, a mouseListener never sees the mouseEvent that is the popupTrigger (reason is that showing the componentPopup is handled globally by a AWTEventListener installed by BasicLookAndFeel, and that listener consumes the event).

The only place which sees the mousePosition of that trigger is the getPopupLocation(MouseEvent), so the only reliable way to get hold of it (for doing location dependent config/actions) is @Mad's suggestion to override that method and store the value somewhere for later use.

The snippet below uses a clientProperty as storage location:

final JTable table = new JTable(new AncientSwingTeam()) {

    @Override
    public Point getPopupLocation(MouseEvent event) {
        setPopupTriggerLocation(event);
        return super.getPopupLocation(event);
    }

    protected void setPopupTriggerLocation(MouseEvent event) {
        putClientProperty("popupTriggerLocation", 
                event != null ? event.getPoint() : null);
    }
};
JPopupMenu popup = new JPopupMenu();
Action action = new AbstractAction("show trigger location") {

    @Override
    public void actionPerformed(ActionEvent e) {
        JPopupMenu parent = (JPopupMenu) SwingUtilities.getAncestorOfClass(
                JPopupMenu.class, (Component) e.getSource());
        JTable invoker = (JTable) parent.getInvoker();
        Point p = (Point) invoker.getClientProperty("popupTriggerLocation");
        String output = p != null ? "row/col: " 
             + invoker.rowAtPoint(p) + "/" + invoker.columnAtPoint(p) : null; 
        System.out.println(output);
    }
};
popup.add(action);
popup.add("dummy2");
table.setComponentPopupMenu(popup);
kleopatra
  • 51,061
  • 28
  • 99
  • 211
3

@MadProgrammer's suggestion of getPopupLocation looked promising, but I couldn't work out how to get the information across between the table and the actionEvent...

I got around this by making sure that the row was selected when you rightclicked on it -> since the popup menu prevents the selection of the row, you can add in a mouse listener that makes sure the row gets selected no matter what click (left or right) is pressed.

aTable.addMouseListener(new MouseAdapter() {
    @Override
    public void mousePressed(MouseEvent e) {
        int r = aTable.rowAtPoint(e.getPoint());
        if (r >= 0 && r < clt.getRowCount()) {
            aTable.setRowSelectionInterval(r, r);
        } else {
            aTable.clearSelection();
        }
    }
});

This means that in the rightClickMenuItem's action listener, you can grab the table's selected cell / row

rightClickMenuItem.addActionListener(new AbstractAction() {
    @Override
    public void actionPerformed(ActionEvent e) {
        aTable.get details about the selected one....
    }
});

Too easy! Thanks everyone for the help.

Community
  • 1
  • 1
Ramo
  • 283
  • 1
  • 5
  • 15
  • after thinking (and testing) again ... the original mouseReleased probably was a kind-of typo, to the edit looks okay after all. Sorry for the fuss. – kleopatra Jun 25 '13 at 10:47
0

JTable has methods

int row = rowAtPoint(p);
int col = columnAtPoint(p);

So pass the MouseEvent's point and use the values

Add a MouseListener and store the last right click point somewhere.

StanislavL
  • 56,971
  • 9
  • 68
  • 98