2011-09-14 12 views
10

come possibile impedire l'attivazione e mostrando JPopupMenu solo se è Mouse Cursor sopra selezionato JTable'RowJTable con JPopupMenu

la mia domanda: se c'è un altro modo come getBounds dalla riga selezionata e determinare/confronto che con Mouse posizione ...

mia semplice sscce dimostrato proprio stato di fronte alla non-voluto, qualsiasi riga potrebbe essere selezionato e JPopupMenu viene attivato da tutto 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

Nice SSCCE a proposito. –

+0

fare. non. sottoclasse. il. _vista_ . per. _modello_. motivi. – kleopatra

+0

La soluzione che ha funzionato meglio per me (anche per kleopatra) non è ancora collegata qui: http://stackoverflow.com/a/17316876/411282 –

risposta

7

E 'una domanda interessante, perché mette in evidenza mancante di API su JComponent :-)

Come tutti sappiamo, il modo consigliato per registrare popupMenus consiste nell'utilizzare la proprietà componentPopupMenu. api correlato è

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

ciò che manca (ed effettivamente necessari per questo requisito) è

JPopupMenu getComponentPopupMenu(MouseEvent); 

questa mancanza è tanto più fastidioso, come è chiamato il getPopupLocation (da AWTEventHelper nel profondo della LAF) dopo getComponentPopup(). Quindi non c'è margine per un hack come memorizzare l'ultimo evento del mouse che potrebbe aver attivato il popup e quindi decidere quale/se restituire il popup. E restituire null per la posizione mostrerà solo nella posizione del mouse

L'unico (sporco) trucco (attorno alla mia totale riluttanza a sporcarmi le mani con un MouseListener ;-) è quello di sovrascrivere getComponentPopup e decidere lì se o di non restituirlo basa sulla posizione del mouse corrente

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

    }; 

l'effetto collaterale è che mostra pop-up non è attivato da tastiera fino a quando il mouse è ovunque sopra il tavolo, che potrebbe o non essere un problema.

+0

grazie per l'elaborazione, quanto è facile imparare ....hehehe, sicuramente il tuo post è la risposta e chiudendo un altro mio problema, il mio +1 – mKorbel

+0

Potrebbe esserci un ulteriore problema, penso, a causa dell'uso di un 'JScrollPane' che incorpora il' JTable'. In passato, ricordo di aver avuto problemi con eventi che non si verificavano su 'JTable' quando facevo clic all'esterno di qualsiasi riga (ma * all'interno * di' JScrollPane', nello spazio vuoto): dovevo ascoltare gli eventi sul 'JScrollP'' stesso (o 'JViewport' non si ricorda esattamente). Quindi forse @mKorbel, devi anche considerare che (ciò dovrebbe accadere ogni volta che 'JScrollPane' è più alto di' JTable'). – jfpoilpret

+0

@jfpoilpret no idea di come sia possibile consumare eventi da Mouse a JViewPort, puoi fornire un esempio sulla creazione di MouseEvents da/su JViewPort, perché ritengo che sia completamente sordo JComponent :-) – mKorbel

12

Stai cercando qualcosa di simile forse?

Per mostrare pop-up sopra le righe selezionate (s) solo

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 il contrario, per evitare che pop-up da mostrare sopra le righe selezionate solo:

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 nonostante il mio diverso punto di vista :). In effetti la tua è una soluzione facile e veloce. – Heisenbug

+1

+1 - una volta che avrai sostituito tutto il ciclo e il controllo manuale di isRowSelected (row) :-) – kleopatra

+1

scusa a tutti. Ho sbagliato completamente. Sembra che quello che voglio fare non sia possibile. Ma @kleopatra, mi piacerebbe sapere: c'è qualche buona ragione per il fatto che i renderer di celle non possano gestire l'evento del mouse? – Heisenbug