34

Short: I need a "right-click event" to highlight the cell row.

I am using a JTable inside a ScrollPane in Java Swing (Netbeans Matisse). I have a MouseClicked event listener on the JTable that does the following:

if (evt.getButton() == java.awt.event.MouseEvent.BUTTON3) {
          System.out.println("Right Click");
          JPopUpMenu.show(myJTable, evt.getX(), evt.getY())
}

The problem is... whenever I execute a right click on the JTable, the row isn't highlighted (I set the selection to rows only btw). I have looked for several setSelected() functions but could not find a suitable one. By default, left clicking automatically highlights the row. How do I set it up for right clicks?

3 Answers3

90

like this:

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

        int rowindex = table.getSelectedRow();
        if (rowindex < 0)
            return;
        if (e.isPopupTrigger() && e.getComponent() instanceof JTable ) {
            JPopupMenu popup = createYourPopUp();
            popup.show(e.getComponent(), e.getX(), e.getY());
        }
    }
});

......

maysi
  • 5,457
  • 12
  • 34
  • 62
clamp
  • 33,000
  • 75
  • 203
  • 299
  • 1
    Just like that :]... the top half of mouseReleased() is what I needed. Will be voted up + accepted as an answer. Thanks, you are the man (or woman)! –  Aug 24 '10 at 16:01
  • 6
    Great answer. A detail: on some platforms (Mac OS X to name it), the popup menu is trigger by `mousePressed` rather than `mouseReleased` so if you use this code the popup won't show up if you run your application on Mac OS X. – gabuzo Dec 31 '12 at 09:31
  • What is the purpose of getting the rowIndex two times? I mean, what is the difference between *r* and *rowindex*? – Ad Infinitum Oct 11 '16 at 10:35
  • Perfect solution. Remember not to use the `setComponentPopupMenu()` method if you're using this solution. – m4heshd Jul 11 '19 at 23:39
  • 1
    See bellow the comment from Oliver Hoffmann Aug 26 '16 at 12:26: There's no need for manual selection handling, the JTable already respects SHIFT and CTRL keys and so on. The only change needed in the original solution is to not use setRowSelectionInterval() in case the focused row already is selected, like: if (!table.getSelectionModel().isSelectedIndex(r)) table.setRowSelectionInterval(r, r); – neflow Jun 24 '20 at 13:42
3

The accepted answer does not take modifier keys like ctrl or shift into account, yet they indicate that the current selection should not be replaced, but extended.

Also, I added multi-OS support by checking mousePressed and mouseReleased.

Following, you can find a complete example on how to adjust the selected rows, using the ListSelectionModel, including MouseEvent#getModifiers checks. After that, it is possible to open a (optional) JPopupMenu.

JPopupMenu contextMenu = new JPopupMenu();
// ...
// add elements to the popup menu
// ...

table.addMouseListener(new MouseAdapter() {
  @Override
  public void mousePressed(MouseEvent e) {
    handleRowClick(e);
    if (e.isPopupTrigger()) {
      doPop(e);
    } else {
      hidePop();
    }
  }

  @Override
  public void mouseReleased(MouseEvent e) {
    if (e.isPopupTrigger()) {
      doPop(e);
    }
  }

  private void handleRowClick(MouseEvent e) {
    ListSelectionModel selectionModel = table.getSelectionModel();
    Point contextMenuOpenedAt = e.getPoint();
    int clickedRow = table.rowAtPoint(contextMenuOpenedAt);

    if (clickedRow < 0) {
      // No row selected
      selectionModel.clearSelection();
    } else {
      // Some row selected
      if ((e.getModifiers() & InputEvent.SHIFT_MASK) == InputEvent.SHIFT_MASK) {
        int maxSelect = selectionModel.getMaxSelectionIndex();

        if ((e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK) {
          // Shift + CTRL
          selectionModel.addSelectionInterval(maxSelect, clickedRow);
        } else {
          // Shift
          selectionModel.setSelectionInterval(maxSelect, clickedRow);
        }
      } else if ((e.getModifiers() & InputEvent.CTRL_MASK) == InputEvent.CTRL_MASK) {
        // CTRL
        selectionModel.addSelectionInterval(clickedRow, clickedRow);
      } else {
        // No modifier key pressed
        selectionModel.setSelectionInterval(clickedRow, clickedRow);
      }
    }
  }

  private void doPop(MouseEvent e) {
    if (table.getSelectedRowCount() == 0) {
      return;
    }
    contextMenu.setVisible(true);
    contextMenu.show(e.getComponent(), e.getX(), e.getY());
  }

  private void hidePop() {
    contextMenu.setVisible(false);
  }
});
Markus Weninger
  • 11,931
  • 7
  • 64
  • 137
  • 2
    There's no need for manual selection handling, the JTable already respects SHIFT and CTRL keys and so on. The only change needed in the original solution is to not use setRowSelectionInterval() in case the focused row already is selected, like: if (!table.getSelectionModel().isSelectedIndex(r)) table.setRowSelectionInterval(r, r); – Oliver Hoffmann Aug 26 '16 at 12:26
0

You can create another MouseEvent (example here is in a JTable subclass; processMouseEvent() has protected access, otherwise could use dispatchEvent() method). Takes care of using the modifiers for the selection update.

addMouseListener(new MouseAdapter() {
    @Override public void mousePressed(MouseEvent e) { checkForPopupMenu(e); }
    @Override public void mouseReleased(MouseEvent e) { checkForPopupMenu(e); }
    private void checkForPopupMenu(MouseEvent e) {
        if (e.isPopupTrigger()) {
            processMouseEvent(new MouseEvent(e.getComponent(), e.getID(), e.getWhen(), e.getModifiersEx(), e.getX(), e.getY(), 1, false, MouseEvent.BUTTON1));
            if (getSelectedRowCount() != 0)
                popup.show(e.getComponent(), e.getX(), e.getY());
        }
    }
});
bourne2program
  • 121
  • 1
  • 5