2009-03-12 8 views
5

¿Hay una manera fácil de manipular los controles en una JTable para proporcionar diferentes funcionalidades cuando se presiona un botón del teclado (es decir, el botón CTRL) y se selecciona una fila? Se me ha pedido que cree una tabla donde el CTRL + clic (clic del mouse) en una fila solo anulará la selección de una fila seleccionada, nunca seleccione una fila. Si el usuario CTRL + hace clic en una fila no seleccionada, no pasará nada.Cambiar el comportamiento de Ctrl + clic en una JTable

He podido crear una tabla y desactivar funciones como CTRL + A (seleccionar todas), y he podido verificar si el botón de control está presionado cuando se genera un evento MouseEvent, pero puedo ' Parece que se da cuenta de cómo se puede ajustar CTRL + Click. Aquí hay algo de código:

package nicky; 

import javax.swing.*; 
import java.awt.Dimension; 
import java.awt.GridLayout; 
import java.awt.event.*; 

public class TableTester extends JPanel { 
    public TableTester() { 
     super(new GridLayout(1,0)); 

     final String[] columnNames = {"First Name", 
             "Last Name", 
             "Sport", 
             "# of Years", 
             "Vegetarian"}; 

     final Object[][] data = { 
      {"Tom", "Roberts","Athletic", new Integer(5), new Boolean(false)}, 
      {"Sarah", "Watt", "Football", new Integer(3), new Boolean(true)}, 
      {"Laura", "Brown", "Swimming", new Integer(2), new Boolean(false)}, 
      {"Simon", "Smith", "Tennis", new Integer(20), new Boolean(true)}, 
      {"Paul", "Jones", "Rugby", new Integer(10), new Boolean(false)} 
     }; 

     JTable table = new JTable(data, columnNames); 
     table.setPreferredScrollableViewportSize(new Dimension(500, 100)); 

     table.setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 

     table.addMouseListener(new MouseListener(){ 
      public void mouseEntered(MouseEvent me){} 
      public void mouseExited(MouseEvent me){} 
      public void mouseReleased(MouseEvent me){} 
      public void mouseClicked(MouseEvent me){} 
      public void mousePressed(MouseEvent me){ 
       if (me.isControlDown()){ 
        System.out.println("This is working "); 
       } 
      } 
     }); 

     InputMap inputMap = table.getInputMap(JTable.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 
     KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_A, InputEvent.CTRL_MASK); 
     inputMap.put(keyStroke, "none"); 

     JScrollPane scrollPane = new JScrollPane(table); 
     add(scrollPane); 
    } 

    private static void createAndShowGUI() { 
     JFrame.setDefaultLookAndFeelDecorated(true); 
     JFrame frame = new JFrame("TableTester"); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     TableTester newContentPane = new TableTester(); 
     newContentPane.setOpaque(true); 
     frame.setContentPane(newContentPane); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     javax.swing.SwingUtilities.invokeLater(new Runnable() { 
      public void run() { 
       createAndShowGUI(); 
      } 
     }); 
    } 
} 

En el método mousePressed He jugado un poco con la obtención de todas las filas seleccionadas de la tabla, y luego iba a comprobar si la fila recién hecho clic en los selectedRows era ... Sin embargo, No estoy seguro de si hay una forma de ver qué fila está asociada con MouseEvent.

(Además, sé comportamiento esperado como este no debe ser jugado con demasiado, pero es replicar un sistema heredado de la empresa)

Cualquier Ideas/sugerencias serán bienvenidos!

Respuesta

8

OK, segunda toma (dejé la primera ya que podría interesar a alguien para otro uso, ¿quién sabe? Diga que está allí para fines educativos ... :-)).

He echado un vistazo al código fuente de JTable y descubrí que los eventos del mouse son manejados por la apariencia. Al saber cómo maneja la tecla de control, pude anular de forma segura el método changeSelection para hacer lo que necesita.
Me parecen un tanto extraños los requisitos (aún puedes usar Mayús + clic, ¿no?) Pero no sé el contexto.

class SpecialTable extends JTable 
{ 
    SpecialTable(Object[][] data, String[] columnNames) 
    { 
     super(data, columnNames); 
// That's already the default   
//  setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 
    } 

    /** 
    * Called by javax.swing.plaf.basic.BasicTableUI.Handler.adjustSelection(MouseEvent) 
    * like: table.changeSelection(pressedRow, pressedCol, e.isControlDown(), e.isShiftDown()); 
    */ 
    @Override 
    public void changeSelection(int rowIndex, int columnIndex, boolean toggle, boolean extend) 
    { 
     if (toggle && !isRowSelected(rowIndex)) 
      return; // Don't do the selection 
     super.changeSelection(rowIndex, columnIndex, toggle, extend); 
    } 
} 

Mucho más simple y exactamente lo que necesita!

Por cierto, gracias por proporcionar un buen caso de prueba tan bueno, podría no haberlo intentado si tuviera que escribirlo yo mismo ... :-D Fue un desafío interesante y de aprendizaje.

+0

Woohoo! ¡Funcionó! Gracias :) Y sí, creo que los requisitos son una locura ... ¡y esto ni siquiera es la mitad! – Nicks

1

que tuvieron éxito con los siguientes, aunque no estoy seguro de que es el mejor método ...

class SpecialTable extends JTable 
{ 
    boolean bIsControlDown; 
    int clickedRow; 

    SpecialTable(Object[][] data, String[] columnNames) 
    { 
     super(data, columnNames); 
//  setSelectionMode(ListSelectionModel.MULTIPLE_INTERVAL_SELECTION); 
     getSelectionModel().addListSelectionListener(this); 
     addMouseListener(new MouseInputAdapter() 
     { 
      public void mousePressed(MouseEvent me) 
      { 
       bIsControlDown = me.isControlDown(); 
       clickedRow = rowAtPoint(me.getPoint()); 
      } 
     }); 
    } 

    public void valueChanged(ListSelectionEvent evt) 
    { 
     super.valueChanged(evt); 
     if (bIsControlDown) 
     { 
      if (!evt.getValueIsAdjusting()) 
      { 
//    System.out.println(evt); 
//    System.out.println("=> " + clickedRow); 
       getSelectionModel().removeSelectionInterval(clickedRow, clickedRow); 
      } 
     } 
    } 
} 

Reemplazar las líneas que definen table en su código con solamente:

JTable table = new SpecialTable(data, columnNames); 
    table.setPreferredScrollableViewportSize(new Dimension(500, 100)); 

Cuando control-clic en una fila no seleccionada, se selecciona brevemente, luego se deselecciona.

+0

Gracias por eso. Desafortunadamente, va a funcionar para mi problema sin embargo. Tan pronto como se selecciona una fila, se apaga el mensaje, por lo que la acción de selección-deselección rápida aún enviará ese mensaje. – Nicks

+0

Me temía eso. Una alternativa es evitar la llamada a super.valueChanged() y gestionar por completo la selección de intervalo múltiple usted mismo (incluso puede copiar el código de Java y modificarlo a su manera, creo). – PhiLho

+0

Es cierto - gracias, creo que voy a dar una oportunidad – Nicks

Cuestiones relacionadas