2011-09-14 16 views
10

¿Cómo puedo prevenir el desencadenamiento y mostrando JPopupMenu sólo si es Mouse Cursor sobre seleccionada JTable'RowJTable con JPopupMenu

mi pregunta: si hay otra manera como getBounds de la fila seleccionada y determinar/compararlo con Mouse posición ...

mi sencilla sscce demostró simplemente el estado opuesto de la ONU querido, cualquier fila podrían seleccionarse y JPopupMenu se activa de todo 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); 
      } 
     }); 
    } 
} 
+2

Niza SSCCE por cierto. –

+0

do. no. subclase. el. _view_. para. _modelo_. razones. – kleopatra

+0

La solución que mejor funcionaba para mí (también por kleopatra) no está vinculada aquí todavía: http://stackoverflow.com/a/17316876/411282 –

Respuesta

7

Es una pregunta interesante, porque pone de manifiesto falta api en JComponent :-)

Como todos sabemos, la forma recomendada de registrar popupMenus es usar la propiedad componentPopupMenu. API relacionada es

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

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

JPopupMenu getComponentPopupMenu(MouseEvent); 

esta falta es tanto más molesto, como se llama el getPopupLocation (por AWTEventHelper profundo de la 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 el valor nulo para la ubicación solo resultará en mostrarlo en la ubicación del mouse

El único truco (sucio) (en torno a mi total renuencia a ensuciarme las manos con un MouseListener ;-) es anular getComponentPopup y decidir si o no devolverlo basa en la posición actual del ratón

table = new JTable(model) { 

     /** 
     * @inherited <p> 
     */ 
     @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 muestra la ventana emergente no se activa por el teclado, siempre y cuando el ratón está en cualquier lugar por encima de la mesa, lo que podría o no ser un problema.

+0

gracias por elaborar, qué fácil es aprender ....jejeje, seguro que su publicación es respuesta y está cerrando otra mi problema, mi +1 – mKorbel

+0

Puede haber un problema adicional, creo, debido al uso de un 'JScrollPane' que incorpora el' JTable'. En el pasado, recuerdo haber tenido problemas con eventos que no ocurrían en 'JTable' al hacer clic fuera de cualquier fila (pero * dentro * de' JScrollPane', en el espacio vacío): tenía que escuchar eventos en 'JScrollPane' (o el 'JViewport' no puede recordar exactamente). Así que tal vez @mKorbel, también tendrás que considerar eso (eso debería suceder siempre que 'JScrollPane' sea más alto que' JTable'). – jfpoilpret

+0

@jfpoilpret no hay idea de cómo es posible consumir eventos desde el Mouse a JViewPort, ¿puedes dar un ejemplo sobre el uso de MouseEvents desde/hacia JViewPort, porque considero que esto es completamente sordo JComponent :-) – mKorbel

12

¿Está buscando algo como esto quizás?

Para mostrar emergente sobre la fila (s) seleccionada solamente

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 a la inversa, para evitar emergente de mostrar más filas seleccionadas solamente:

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()); 
     } 
    } 
+1

+1 a pesar de mi punto de vista diferente :). En efecto, la suya es una solución fácil y rápida. – Heisenbug

+1

+1 - una vez que haya reemplazado todo ese bucle y la comprobación manual por isRowSelected (fila) :-) – kleopatra

+1

disculpe a todos. Estaba completamente equivocado. Parece que lo que quiero hacer, no es posible. Pero @kleopatra, me gustaría saber: ¿hay alguna buena razón para que los procesadores de células no puedan manejar el evento del mouse? – Heisenbug