【问题标题】:Change the Ctrl + click behaviour on a JTable更改 JTable 上的 Ctrl + 单击行为
【发布时间】:2010-10-12 23:15:33
【问题描述】:

当按下键盘按钮(即 CTRL 按钮)并选择一行时,是否有一种简单的方法来操作 JTable 上的控件以提供不同的功能?我被要求创建一个表格,其中一行上的 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 关联的行的方法。

(另外,我知道这样的预期行为不应该玩太多,而是在公司中复制遗留系统)

任何想法/建议将不胜感激!

【问题讨论】:

    标签: java swing jtable


    【解决方案1】:

    好的,第二次拍摄(我留下了第一个,因为它可能会引起其他人的兴趣,谁知道呢?说它是为了教育目的...... :-))。

    我查看了 JTable 的源代码,发现鼠标事件是由外观处理的。知道它如何处理控制键后,我可以安全地重写 changeSelection 方法来完成您需要的操作。
    我觉得要求有点奇怪(你仍然可以使用 Shift+click,不是吗?)但我不知道上下文。

    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 这是一个有趣且学习的挑战。

    【讨论】:

    • 哇哦!有效!谢谢 :) 是的,我认为要求很疯狂......这甚至不是它的一半!
    【解决方案2】:

    我在以下方面取得了成功,尽管我不确定这是最好的方法...

    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 键单击未选择的行时,它会短暂地被选中,然后被取消选择。

    【讨论】:

    • 谢谢。不幸的是,它会解决我的问题。一旦选择了一行,它就会触发消息,因此快速选择-取消选择操作仍会发送该消息。
    • 我担心这一点。另一种方法是避免调用 super.valueChanged() 并自己完全处理多区间选择(我认为甚至可以复制 Java 的代码并按照自己的方式进行更改)。
    猜你喜欢
    • 1970-01-01
    • 2014-07-13
    • 2012-03-18
    • 1970-01-01
    • 1970-01-01
    • 2011-09-23
    • 2011-08-18
    • 1970-01-01
    • 2018-07-27
    相关资源
    最近更新 更多