2012-06-21 8 views
10

"Esiste un modo per impedire a JList di selezionare l'ultimo elemento quando l'utente fa clic su di esso nell'elenco?"Come impedire a JList di effettuare la selezione al di fuori dei limiti di cella?

Questa è la domanda che qualcuno ha chiesto here e ho lo stesso problema. Quel ragazzo ha trovato una soluzione così così (superando processMouseEvent()) ma voglio sapere se c'è un modo migliore/più elegante per farlo.

[Modifica]

Ok, maggiori dettagli. Se si dispone di una JList e c'è qualche spazio libero da una cella/elemento e si fa clic su tale spazio, viene selezionato l'ultimo elemento nella JList.

Per un esempio reale prova questo JList Swing Tutorial example, fai clic sullo spazio bianco e vedi che Rollo è stato selezionato.

+0

SO isn' t generatore di codice, per un aiuto migliore prima inserisci un [SSCCE] (http://sscce.org/), altrimenti la mia risposta è ampia come la tua domanda semplice da 'consumare' – mKorbel

+0

@GuillaumePolet thnx, completamente trascurato quell'aspetto – Alex

+0

@mKorbel semplice esempio aggiunto – Alex

risposta

16

Vedere https://forums.oracle.com/forums/thread.jspa?threadID=2206996

import java.awt.EventQueue; 
import java.awt.Point; 
import java.awt.Toolkit; 
import java.awt.event.InputEvent; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 

import javax.swing.JFrame; 
import javax.swing.JList; 
import javax.swing.JScrollPane; 

public class TestJList { 
    public static void main(String[] args) { 
     EventQueue.invokeLater(new Runnable() { 
      public void run() { 
       JList list = new JList(new Object[] { "One", "Two", "Three" }) { 
        @Override 
        public int locationToIndex(Point location) { 
         int index = super.locationToIndex(location); 
         if (index != -1 && !getCellBounds(index, index).contains(location)) { 
          return -1; 
         } 
         else { 
          return index; 
         } 
        } 
       }; 

       list.addMouseListener(new MouseAdapter() { 

        @Override 
        public void mouseClicked(MouseEvent e) { 
         JList list = (JList) e.getSource(); 
         if (list.locationToIndex(e.getPoint()) == -1 && !e.isShiftDown() 
           && !isMenuShortcutKeyDown(e)) { 
          list.clearSelection(); 
         } 
        } 

        private boolean isMenuShortcutKeyDown(InputEvent event) { 
         return (event.getModifiers() & Toolkit.getDefaultToolkit() 
           .getMenuShortcutKeyMask()) != 0; 
        } 
       }); 

       JFrame frame = new JFrame("Test"); 
       frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
       frame.getContentPane().add(new JScrollPane(list)); 
       frame.pack(); 
       frame.setLocationRelativeTo(null); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 
+0

+1 codice eccellente, da entrambi i poster su OTN, per favore dov'è l'elenco di tutti i built-in 'putClientProperty (...)' nelle API Swing – mKorbel

+1

Considerare anche leggendo il commento di Kleopatra sotto la risposta. Potrebbe essere un po 'scomodo cancellare la selezione. La mia aspettativa sarebbe stata che non succedesse nulla. Se ho fatto una selezione valida in precedenza (e non necessariamente l'ultima cella) e poi faccio clic all'esterno di JList, vorrei che la selezione rimanesse, non per essere cancellata –

2

Guardando lo stack di chiamate, non si può davvero fare quello che vuoi senza fare confusione con AWT-Events:

Thread [AWT-EventQueue-0] (Suspended (breakpoint at line 384 in DefaultListSelectionModel)) 
    DefaultListSelectionModel.changeSelection(int, int, int, int, boolean) line: 384  
    DefaultListSelectionModel.changeSelection(int, int, int, int) line: 415 
    DefaultListSelectionModel.setSelectionInterval(int, int) line: 459 
    TestJList$1(JList<E>).setSelectionInterval(int, int) line: 2067 
    BasicListUI$Handler.adjustSelection(MouseEvent) line: 2739 
    BasicListUI$Handler.mousePressed(MouseEvent) line: 2695 
    AWTEventMulticaster.mousePressed(MouseEvent) line: 280 
    TestJList$1(Component).processMouseEvent(MouseEvent) line: 6502 
    TestJList$1(JComponent).processMouseEvent(MouseEvent) line: 3321  
    TestJList$1.processMouseEvent(MouseEvent) line: 24 
    TestJList$1(Component).processEvent(AWTEvent) line: 6270  
    TestJList$1(Container).processEvent(AWTEvent) line: 2229  
    TestJList$1(Component).dispatchEventImpl(AWTEvent) line: 4861 
    TestJList$1(Container).dispatchEventImpl(AWTEvent) line: 2287 
    TestJList$1(Component).dispatchEvent(AWTEvent) line: 4687 
    LightweightDispatcher.retargetMouseEvent(Component, int, MouseEvent) line: 4832 
    LightweightDispatcher.processMouseEvent(MouseEvent) line: 4489 
    LightweightDispatcher.dispatchEvent(AWTEvent) line: 4422  
    JFrame(Container).dispatchEventImpl(AWTEvent) line: 2273  
    JFrame(Window).dispatchEventImpl(AWTEvent) line: 2713 
    JFrame(Component).dispatchEvent(AWTEvent) line: 4687  
    EventQueue.dispatchEventImpl(AWTEvent, Object) line: 707  
    EventQueue.access$000(EventQueue, AWTEvent, Object) line: 101 
    EventQueue$3.run() line: 666  
    EventQueue$3.run() line: 664  
    AccessController.doPrivileged(PrivilegedAction<T>, AccessControlContext) line: not available [native method]  
    ProtectionDomain$1.doIntersectionPrivilege(PrivilegedAction<T>, AccessControlContext, AccessControlContext) line: 76  
    ProtectionDomain$1.doIntersectionPrivilege(PrivilegedAction<T>, AccessControlContext) line: 87 
    EventQueue$4.run() line: 680  
    EventQueue$4.run() line: 678  

Si potrebbe implementare il proprio ListUI e poi fai tutto ciò che vuoi (compreso prevenire questo comportamento indesiderato), ma non raccomanderei davvero di seguire questa strada.

Per quel che vale (è fatto sovrascrivendo i metodi processXXXEvent), ecco un piccolo frammento che io in realtà trovo non quella brutta e che impedisce la selezione degli oggetti quando si fa clic di fuori dei loro confini:

import java.awt.event.MouseEvent; 

import javax.swing.JFrame; 
import javax.swing.JList; 
import javax.swing.JScrollPane; 
import javax.swing.SwingUtilities; 

public class TestJList { 

    private JList list; 

    protected void initUI() { 
     JFrame frame = new JFrame("test"); 
     list = new JList(new Object[] { "Hello", "World", "!" }) { 

      private boolean processEvent(MouseEvent e) { 
       int index = list.locationToIndex(e.getPoint()); 
       return index > -1 && list.getCellBounds(index, index).contains(e.getPoint()); 
      } 

      @Override 
      protected void processMouseEvent(MouseEvent e) { 
       if (processEvent(e)) { 
        super.processMouseEvent(e); 
       } 
      } 

      @Override 
      protected void processMouseMotionEvent(MouseEvent e) { 
       if (processEvent(e)) { 
        super.processMouseMotionEvent(e); 
       } 
      } 
     }; 
     list.setVisibleRowCount(10); 

     frame.add(new JScrollPane(list)); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       new TestJList().initUI(); 
      } 
     }); 
    } 
}