JTable con JPopupMenu

¿Cómo puedo evitar disparar y mostrar JPopupMenu solo si el Mouse Cursor está sobre JTable'Row seleccionado JTable'Row

mi pregunta: si hay otra forma como getBounds de la fila seleccionada y determinar / comparar eso con la posición del Mouse

mi sscce simple demostró estado opuesto no deseado, cualquier fila podría ser seleccionada y JPopupMenu se activa desde toda JTable

 import java.awt.event.*; import javax.swing.*; import javax.swing.table.*; public class TableCheckBox extends JFrame { private static final long serialVersionUID = 1L; private JTable table; public TableCheckBox() { Object[] columnNames = {"Type", "Company", "Shares", "Price", "Boolean"}; Object[][] data = { {"Buy", "IBM", new Integer(1000), new Double(80.50), false}, {"Sell", "MicroSoft", new Integer(2000), new Double(6.25), true}, {"Sell", "Apple", new Integer(3000), new Double(7.35), true}, {"Buy", "Nortel", new Integer(4000), new Double(20.00), false} }; DefaultTableModel model = new DefaultTableModel(data, columnNames); table = new JTable(model) { private static final long serialVersionUID = 1L; @Override public Class getColumnClass(int column) { return getValueAt(0, column).getClass(); } }; table.setPreferredScrollableViewportSize(table.getPreferredSize()); JScrollPane scrollPane = new JScrollPane(table); add(scrollPane); createPopupMenu(); } private void createPopupMenu() { JPopupMenu popup = new JPopupMenu(); JMenuItem myMenuItem1 = new JMenuItem("cccccccccccccccccccccc"); JMenuItem myMenuItem2 = new JMenuItem("bbbbbbbbbbbbbbbbbbbbbb"); popup.add(myMenuItem1); popup.add(myMenuItem2); MouseListener popupListener = new PopupListener(popup); table.addMouseListener(popupListener); } private class PopupListener extends MouseAdapter { private JPopupMenu popup; PopupListener(JPopupMenu popupMenu) { popup = popupMenu; } @Override public void mousePressed(MouseEvent e) { maybeShowPopup(e); } @Override public void mouseReleased(MouseEvent e) { if (table.getSelectedRow() != -1) { maybeShowPopup(e); } } private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { TableCheckBox frame = new TableCheckBox(); frame.setDefaultCloseOperation(EXIT_ON_CLOSE); frame.pack(); frame.setLocation(150, 150); frame.setVisible(true); } }); } } 

Es una pregunta interesante, porque destaca la API que falta en JComponent 🙂

Como todos sabemos, la forma recomendada de registrar popupMenus es usar la propiedad componentPopupMenu. Api relacionado es

  void setComponentPopupMenu(JPopupMenu); JPopupMenu getComponentPopupMenu(); Point getPopupLocation(MouseEvent); 

lo que falta (y realmente se necesita para este requisito) es

 JPopupMenu getComponentPopupMenu(MouseEvent); 

esta falta es aún más molesta, ya que getPopupLocation se llama (por AWTEventHelper en las profundidades de LAF) después de getComponentPopup (). Por lo tanto, no hay margen de maniobra para un truco como almacenar el último evento del mouse que podría haber desencadenado la ventana emergente y luego decidir qué / if devolver ventana emergente. Y devolver nulo para la ubicación solo dará como resultado que se muestre en la ubicación del mouse

El único truco (sucio) (en torno a mi absoluta renuencia a ensuciarme las manos con un MouseListener 😉 es anular getComponentPopup y decidir si devolverlo o no según la posición actual del mouse

  table = new JTable(model) { /** * @inherited 

*/ @Override public JPopupMenu getComponentPopupMenu() { Point p = getMousePosition(); // mouse over table and valid row if (p != null && rowAtPoint(p) >= 0) { // condition for showing popup triggered by mouse if (isRowSelected(rowAtPoint(p))) { return super.getComponentPopupMenu(); } else { return null; } } return super.getComponentPopupMenu(); } };

el efecto secundario es que la aparición de una ventana emergente no es activada por el teclado, siempre y cuando el mouse esté sobre la mesa, lo que podría o no ser un problema.

¿Estás buscando algo como esto tal vez?

Para mostrar emergente solo sobre la (s) fila (s) seleccionada (s)

  private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { // get row that pointer is over int row = table.rowAtPoint(e.getPoint()); // if pointer is over a selected row, show popup if (table.isRowSelected(row)) { popup.show(e.getComponent(), e.getX(), e.getY()); } } } 

O lo contrario, para evitar que la ventana emergente solo se muestre en las filas seleccionadas:

  private void maybeShowPopup(MouseEvent e) { if (e.isPopupTrigger()) { int row = table.rowAtPoint(e.getPoint()); int[] selectedRows = table.getSelectedRows(); if (!table.isRowSelected(row)) { popup.show(e.getComponent(), e.getX(), e.getY()); } }