Java Swing JTable; Right Click Menu (How do I get it to "select" aka highlight the row)
Asked Answered
J

3

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?

Jezabelle answered 24/8, 2010 at 15:47 Comment(0)
M
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());
        }
    }
});

......

Michi answered 24/8, 2010 at 15:50 Comment(5)
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)!Jezabelle
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.Apocrypha
What is the purpose of getting the rowIndex two times? I mean, what is the difference between r and rowindex?Abrasive
Perfect solution. Remember not to use the setComponentPopupMenu() method if you're using this solution.Scholasticism
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);Konya
S
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);
  }
});
Stavros answered 1/8, 2016 at 16:42 Comment(1)
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);Dehiscent
B
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());
        }
    }
});
Beastly answered 4/2, 2022 at 19:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.