Selección celular individual y no continua de JTable

¿Hay alguna forma limpia de permitir que un usuario seleccione múltiples celdas no continuas de una JTable? ¿O me veo obligado a implementar mi propio ListSelectionModel?

Jugué con los métodos setCellSelectionEnabled () y setSelectionModel () en JTable pero solo puedo seleccionar grupos de celdas continuas.

EDITAR:

Intenté @mKorbel nice SSCCE. Funciona bien para la lista pero parece no funcionar completamente en las tablas. Aquí hay un SSCCE:

import java.awt.Component; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JScrollPane; import javax.swing.JTable; public class TableSelection extends JFrame{ String[] columnNames = {"First Name", "Last Name", "Sport", "# of Years", "Vegetarian"}; Object[][] data = { {"Kathy", "Smith", "Snowboarding", new Integer(5), new Boolean(false)}, {"John", "Doe", "Rowing", new Integer(3), new Boolean(true)}, {"Sue", "Black", "Knitting", new Integer(2), new Boolean(false)}, {"Jane", "White", "Speed reading", new Integer(20), new Boolean(true)}, {"Joe", "Brown", "Pool", new Integer(10), new Boolean(false)} }; public TableSelection(){ JPanel main= new JPanel(); JTable table = new JTable(data, columnNames){ @Override protected void processMouseEvent(MouseEvent e) { int modifiers = e.getModifiers() | InputEvent.CTRL_MASK; // change the modifiers to believe that control key is down int modifiersEx = e.getModifiersEx() | InputEvent.CTRL_MASK; // can I use this anywhere? I don't see how to change the modifiersEx of the MouseEvent MouseEvent myME = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), modifiers, e.getX(), e.getY(), e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), e.isPopupTrigger(), e.getButton()); super.processMouseEvent(myME); } }; JScrollPane pane = new JScrollPane(table); main.add(pane); this.add(main); this.setSize(800, 600); this.setVisible(true); } /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub new TableSelection(); } } 

Puedo seleccionar una fila no contigua pero no una sola celda. Quiero decir, me gustaría poder seleccionar la celda 0,0 y 3,3 por ejemplo.

  1. Si no está definido para JTable#setSelectionMode(ListSelectionModel.SINGLE_SELECTION) , entonces CTRL + MOUSE_CLICK

  2. ¿O quieres decir recordar la última selección?

  3. ListSelectionModel es utilizado tanto por JTable como por JList .

enter image description hereenter image description hereenter image description hereenter image description hereenter image description here

 import java.awt.Component; import java.awt.event.InputEvent; import java.awt.event.MouseEvent; import javax.swing.*; public class Ctrl_Down_JList { private static void createAndShowUI() { String[] items = {"Sun", "Mon", "Tues", "Wed", "Thurs", "Fri", "Sat"}; JList myJList = new JList(items) { private static final long serialVersionUID = 1L; @Override protected void processMouseEvent(MouseEvent e) { int modifiers = e.getModifiers() | InputEvent.CTRL_MASK; // change the modifiers to believe that control key is down int modifiersEx = e.getModifiersEx() | InputEvent.CTRL_MASK; // can I use this anywhere? I don't see how to change the modifiersEx of the MouseEvent MouseEvent myME = new MouseEvent((Component) e.getSource(), e.getID(), e.getWhen(), modifiers, e.getX(), e.getY(), e.getXOnScreen(), e.getYOnScreen(), e.getClickCount(), e.isPopupTrigger(), e.getButton()); super.processMouseEvent(myME); } }; JFrame frame = new JFrame("Ctrl_Down_JList"); frame.getContentPane().add(new JScrollPane(myJList)); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } public static void main(String[] args) { java.awt.EventQueue.invokeLater(new Runnable() { @Override public void run() { createAndShowUI(); } }); } 

Use MULTIPLE_INTERVAL_SELECTION , que se muestra en Cómo usar tablas: selecciones de usuario .

Adición: Debido a que el MULTIPLE_INTERVAL_SELECTION de ListSelectionModel también está disponible para JList , puede aprovechar el HORIZONTAL_WRAP de este último para obtener una selección no contigua, como se muestra a continuación.

enter image description here

Consola:

 [Célula: 06]
 [Célula: 06, Célula: 16]
 [Célula: 06, Célula: 16, Célula: 18]
 [Célula: 06, Célula: 08, Célula: 16, Célula: 18]

Código:

 import java.awt.*; import java.util.Arrays; import javax.swing.*; import javax.swing.event.*; /** * @see http://stackoverflow.com/questions/7620579 * @see http://stackoverflow.com/questions/4176343 */ public class ListPanel extends JPanel { private static final int N = 5; private DefaultListModel dlm = new DefaultListModel(); private JList list = new JList(dlm); public ListPanel() { super(new GridLayout()); for (int i = 0; i < N * N; i++) { String name = "Cell:" + String.format("%02d", i); dlm.addElement(name); } list.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); list.setLayoutOrientation(JList.HORIZONTAL_WRAP); list.setVisibleRowCount(N); list.setCellRenderer(new ListRenderer()); list.addListSelectionListener(new SelectionHandler()); this.add(list); } private class ListRenderer extends DefaultListCellRenderer { public ListRenderer() { this.setBorder(BorderFactory.createLineBorder(Color.red)); } @Override public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) { JComponent jc = (JComponent) super.getListCellRendererComponent( list, value, index, isSelected, cellHasFocus); jc.setBorder(BorderFactory.createEmptyBorder(N, N, N, N)); return jc; } } private class SelectionHandler implements ListSelectionListener { @Override public void valueChanged(ListSelectionEvent e) { if (!e.getValueIsAdjusting()) { System.out.println(Arrays.toString(list.getSelectedValues())); } } } private void display() { JFrame f = new JFrame("ListPanel"); f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); f.add(this); f.pack(); f.setLocationRelativeTo(null); f.setVisible(true); } public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { @Override public void run() { new ListPanel().display(); } }); } }