Pregunta

¿Hay una manera fácil de manipular los controles en una JTable para proporcionar una funcionalidad diferente 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 CTRL + clic (clic del mouse) en una fila solo deseleccione una fila seleccionada, nunca seleccione una fila. Si el usuario CTRL + hace clic en una fila no seleccionada, no sucederá nada.

He podido crear una tabla y deshabilitar funciones como CTRL + A (seleccionar todo), y he podido comprobar si se presiona el botón de control cuando se genera un MouseEvent, pero no puedo parece darse cuenta de cómo se puede ajustar CTRL + Click. Aquí hay un 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 con la obtención de todas las filas seleccionadas de la tabla, y luego iba a verificar si la fila recién seleccionada estaba en las filas seleccionadas ... Sin embargo, no estoy seguro de si hay una forma de ver qué fila está asociada con MouseEvent.

(Además, sé que el comportamiento esperado como este no debería jugarse con demasiado, pero es para replicar un sistema heredado en la empresa)

Cualquier idea / sugerencia sería apreciada!

¿Fue útil?

Solución

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

Eché un vistazo al código fuente de JTable y descubrí que los eventos del mouse son manejados por la apariencia. Sabiendo cómo maneja la tecla de control, podría anular con seguridad el método changeSelection para hacer lo que necesita.
Los requisitos me parecen un poco extraños (todavía puedes usar Shift + clic, ¿no?) Pero no conozco 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 necesitas!

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

Otros consejos

Tuve éxito con lo siguiente, aunque no estoy seguro de que sea 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);
            }
        }
    }
}

Reemplace las líneas que definen la tabla en su código con solo:

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

Cuando controlas y haces clic en una fila no seleccionada, se selecciona brevemente y luego no se selecciona.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top