Есть ли простой способ манипулировать элементами управления в JTable для предоставления различных функций, когда на клавиатуре нажата кнопка (например, кнопка CTRL) и выбрана строка? Меня попросили создать таблицу, в которой CTRL + щелчок (щелчок мышью) на строке снимает выделение только с выбранной строки, но никогда не выбирает строку. Если пользователь CTRL + щелкает невыделенную строку, ничего не произойдет.

Мне удалось создать таблицу и отключить такие функции, как CTRL + A (выбрать все), и я смог проверить, нажата ли кнопка управления при генерации MouseEvent, но я не могу понять узнайте, как можно настроить CTRL + Click. Вот код:

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

В методе mousePressed я поигрался с получением всех выбранных строк из таблицы, а затем собирался проверить, находится ли вновь выбранная строка в selectedRows ... Однако я не уверен, есть ли способ посмотрите, какая строка связана с MouseEvent.

(Кроме того, я знаю, что с ожидаемым поведением, таким как это, не стоит слишком много экспериментировать, это необходимо для того, чтобы воспроизвести устаревшую систему в компании)

Любые идеи / предложения будут оценены!

5
Nicks 12 Мар 2009 в 19:19

2 ответа

Лучший ответ

Хорошо, второй дубль (я оставил первый, так как он может кого-нибудь заинтересовать для другого использования, кто знает? Скажем, он здесь для образовательных целей ... :-)).

Я просмотрел исходный код JTable и обнаружил, что события мыши обрабатываются внешним видом. Зная, как он обрабатывает управляющую клавишу, я мог безопасно переопределить метод changeSelection, чтобы делать то, что вам нужно.
Я нахожу требования немного странными (вы все еще можете использовать Shift + щелчок, не так ли?), Но я не знаю контекста.

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

Намного проще и именно то, что вам нужно!

Кстати, спасибо за такой простой хороший тестовый пример, я бы, возможно, не пробовал, если бы мне пришлось написать его самому ... :-D Это была интересная и обучающая задача.

10
PhiLho 13 Мар 2009 в 17:17
Woohoo! Это сработало! Спасибо :) И да, я считаю, что требования сумасшедшие ... и это даже не половина!
 – 
Nicks
13 Мар 2009 в 17:52

Я добился успеха со следующим, хотя я не уверен, что это лучший метод ...

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

Замените в коде строки, определяющие table, только на:

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

Когда вы нажимаете невыделенную строку, удерживая клавишу Control, она на короткое время выделяется, а затем отменяется.

1
PhiLho 12 Мар 2009 в 20:58
Спасибо за это. К сожалению, это сработает для моей проблемы. Как только строка выбрана, она запускает сообщение, поэтому действие быстрого выбора-отмены выбора все равно отправит это сообщение.
 – 
Nicks
13 Мар 2009 в 13:42
Я этого боялся. Альтернативой является избегать вызова super.valueChanged () и полностью обрабатывать выбор нескольких интервалов самостоятельно (я думаю, можно даже скопировать код Java и изменить его по-своему).
 – 
PhiLho
13 Мар 2009 в 15:01