键绑定不适用于某些键,如插入,删除

时间:2016-02-22 08:34:28

标签: java swing jtable key-bindings

我尝试绑定JTable的快捷方式,它可以正常使用Alphabets,但不适用于InsertDeleteSpace这样的密钥等

对于Ex,以下代码适用于Ctrl+I或任何字母表,但如果我选择Ctrl+Insert它不能正常工作,为什么会这样?

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.table.DefaultTableModel;

public class NewClass {
public static void main(String args[]) {

    try {
        for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
            if ("Windows".equals(info.getName())) {
                javax.swing.UIManager.setLookAndFeel(info.getClassName());
                break;
            }
        }
    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
        java.util.logging.Logger.getLogger(NewClass.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
    }

    java.awt.EventQueue.invokeLater(new Runnable() {
        @Override
        public void run() {
            JFrame frame = new JFrame();
            frame.setLayout(new BorderLayout());
            frame.add(new JScrollPane(createTable()), BorderLayout.CENTER);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setSize(400, 500);
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
    });
}

public static JTable createTable() {
    DefaultTableModel tmodel = new DefaultTableModel(3, 5);
    JTable table = new JTable(tmodel);
    table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_MASK), "Insert");
    //Not working for VK_INSERT or VK_DELETE or VK_SPACE
    table.getActionMap().put("Insert", new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent e) {
            System.out.println("Insert Action");
        }
    });
    return table;
}

}

更新1

使用WHEN_IN_FOCUSED_WINDOW时无效,但如果我选择WHEN_FOCUSEDWHEN_ANCESTOR_OF_FOCUSED_COMPONENT

,则无法正常工作

3 个答案:

答案 0 :(得分:1)

  • 需要WHEN_ANCESTOR_OF_FOCUSED_COMPONENT作为焦点的核心设置(隐藏在JScrolPane s JViewport后面)
  

<强> JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT

     

组件包含(或是)具有焦点的组件。此输入映射通常用于复合组件 - a   实现依赖于子组件的组件。对于   例如,JTables使用它们的所有绑定   WHEN_ANCESTOR_OF_FOCUSED_COMPONENT如果用户正在编辑,则   向上箭头键(例如)仍然会更改所选单元格。

  • 然后来自OPs问题和评论的所有KeyEvent组合在Win7 / Win10,Java7 / Java8中正确地起作用,也来自MadProgrammer的删除帖子(users_rep&gt; 10k)

  • AFAIK有restiction,有多个修饰符,如果是&gt; 2,然后CTRL + ALT + SHIFT + Whatever可以从AWTEventListener或从非常复杂的KeyListener

  • 中抓取

SSCCE / MCVE表格中的模拟代码

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.table.DefaultTableModel;

public class NewClass {

    public static void main(String args[]) {
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info
                    : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Windows".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException |
                IllegalAccessException | javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(
                    NewClass.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.setLayout(new BorderLayout());
                frame.add(new JScrollPane(createTable()), BorderLayout.CENTER);
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setSize(400, 500);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public static JTable createTable() {
        DefaultTableModel tmodel = new DefaultTableModel(3, 5);
        JTable table = new JTable(tmodel);
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, KeyEvent.CTRL_MASK), "Insert");
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.CTRL_MASK), "Insert");
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.CTRL_MASK), "Insert");
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_MASK), "Insert");
        table.getActionMap().put("Insert", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Action from JTable");
            }
        });
        return table;
    }
}

答案 1 :(得分:1)

没有选择

Delete Action from JTable
Insert Action from JTable
Space Action from JTable
I Action from JTable

选择单元格后

    Delete Action from JTable
    Insert Action from JTable
    Space Action from JTable
    I Action from JTable

从代码中,为了正确性是必需的(否则有一堆unilteres事件,但为了测试目的而完成)来测试CTRL&amp;&amp;无论是什么被压入内部的AWTEventListener

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JViewport;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
import javax.swing.table.DefaultTableModel;

public class NewClass {

    private JFrame frame = new JFrame();
    private DefaultTableModel tmodel = new DefaultTableModel(3, 5);
    private JTable table = new JTable(tmodel);

    public NewClass() {
        frame.add(new JScrollPane(createTable()), BorderLayout.CENTER);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setLocation(150, 150);
        frame.setVisible(true);
        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {

            @Override
            public void eventDispatched(AWTEvent event) {
                if (event instanceof KeyEvent) {
                    KeyEvent ke = (KeyEvent) event;
                    Component comp = ke.getComponent();
                    if (comp instanceof JTable) {
                        System.out.println(comp);
                    } else if (comp instanceof JScrollPane) {
                        System.out.println(comp);
                    } else if (comp instanceof JViewport) {
                        System.out.println(comp);
                    } else if (comp instanceof JFrame) {
                        System.out.println(comp);
                    } else {
                        System.out.println(comp);
                    }
                }
            }
        }, AWTEvent.KEY_EVENT_MASK);
    }

    public JTable createTable() {
        table.setPreferredScrollableViewportSize(table.getPreferredSize());
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, KeyEvent.CTRL_MASK), "Delete");
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.CTRL_MASK), "Insert");
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, KeyEvent.CTRL_MASK), "Space");
        table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(
                KeyStroke.getKeyStroke(KeyEvent.VK_I, KeyEvent.CTRL_MASK), "I");
        table.getActionMap().put("Delete", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Delete Action from JTable");
            }
        });
        table.getActionMap().put("Insert", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Insert Action from JTable");
            }
        });
        table.getActionMap().put("Space", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("Space Action from JTable");
            }
        });
        table.getActionMap().put("I", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.out.println("I Action from JTable");
            }
        });
        return table;
    }

    public static void main(String args[]) {
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info
                    : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Windows".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException | InstantiationException |
                IllegalAccessException |
                javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(
                    NewClass.class.getName()).log(
                            java.util.logging.Level.SEVERE, null, ex);
        }
        java.awt.EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new NewClass();
            }
        });
    }
}

答案 2 :(得分:1)

由Rob(camickr)制作的代码,打印出KeyBindings(抱歉,我没有指向他和Darryls代码的链接......)

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;
import javax.swing.*;
import javax.swing.border.*;
import javax.swing.table.*;
import javax.swing.filechooser.*;

public class KeyBindings implements ItemListener {

    private static final String PACKAGE = "javax.swing.";
    private static final String[] COLUMN_NAMES = {"Action", "When Focused", 
        "When In Focused Window", "When Ancestor"};
    private static String selectedItem;
    private JComponent contentPane;
    private JMenuBar menuBar;
    private JTable table;
    private JComboBox comboBox;
    private Hashtable<String, DefaultTableModel> models;

    public KeyBindings() {
        models = new Hashtable<String, DefaultTableModel>();
        contentPane = new JPanel(new BorderLayout());
        contentPane.add(buildNorthComponent(), BorderLayout.NORTH);
        contentPane.add(buildCenterComponent(), BorderLayout.CENTER);
        resetComponents();
    }

    public JComponent getContentPane() {
        return contentPane;
    }

    public JMenuBar getMenuBar() {
        if (menuBar == null) {
            menuBar = createMenuBar();
        }
        return menuBar;
    }

    private JComponent buildNorthComponent() {
        comboBox = new JComboBox();
        JLabel label = new JLabel("Select Component:");
        label.setDisplayedMnemonic('S');
        label.setLabelFor(comboBox);
        JPanel panel = new JPanel();
        panel.setBorder(new EmptyBorder(15, 0, 15, 0));
        panel.add(label);
        panel.add(comboBox);
        return panel;
    }

    private String checkForUIKey(String key) {
        if (key.endsWith("UI") && key.indexOf(".") == -1) {
            String componentName = key.substring(0, key.length() - 2);
            if (componentName.equals("PopupMenuSeparator")
                    || componentName.equals("ToolBarSeparator")
                    || componentName.equals("DesktopIcon")) {
                return null;
            } else {
                return componentName;
            }
        }
        return null;
    }

    private JComponent buildCenterComponent() {
        DefaultTableModel model = new DefaultTableModel(COLUMN_NAMES, 0);
        table = new JTable(model) {

            private static final long serialVersionUID = 1L;

            @Override
            public boolean isCellEditable(int row, int column) {
                return false;
            }
        };
        table.setAutoCreateColumnsFromModel(false);
        table.getColumnModel().getColumn(0).setPreferredWidth(200);
        table.getColumnModel().getColumn(1).setPreferredWidth(200);
        table.getColumnModel().getColumn(2).setPreferredWidth(200);
        table.getColumnModel().getColumn(3).setPreferredWidth(200);
        Dimension d = table.getPreferredSize();
        d.height = 350;
        table.setPreferredScrollableViewportSize(d);
        table.getTableHeader().setFocusable(true);
        return new JScrollPane(table);
    }

    public void resetComponents() {
        models.clear();
        Vector<String> comboBoxItems = new Vector<String>(50);
        UIDefaults defaults = UIManager.getLookAndFeelDefaults();
        for (Object key : defaults.keySet()) {
            String componentName = checkForUIKey(key.toString());
            if (componentName != null) {
                comboBoxItems.add(componentName);
            }
        }
        Collections.sort(comboBoxItems);
        comboBox.removeItemListener(this);
        comboBox.setModel(new DefaultComboBoxModel(comboBoxItems));
        comboBox.setSelectedIndex(-1);
        comboBox.addItemListener(this);
        comboBox.requestFocusInWindow();
        if (selectedItem != null) {
            comboBox.setSelectedItem(selectedItem);
        }
    }

    private JMenuBar createMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        menuBar.add(createFileMenu());
        menuBar.add(createLAFMenu());
        return menuBar;
    }

    private JMenu createFileMenu() {
        JMenu menu = new JMenu("Application");
        menu.setMnemonic('A');
        menu.addSeparator();
        menu.add(new ExitAction());
        return menu;
    }

    private JMenu createLAFMenu() {
        ButtonGroup bg = new ButtonGroup();
        JMenu menu = new JMenu("Look & Feel");
        menu.setMnemonic('L');
        String lafId = UIManager.getLookAndFeel().getID();
        UIManager.LookAndFeelInfo[] lafInfo = UIManager.getInstalledLookAndFeels();
        for (int i = 0; i < lafInfo.length; i++) {
            String laf = lafInfo[i].getClassName();
            String name = lafInfo[i].getName();
            Action action = new ChangeLookAndFeelAction(laf, name);
            JRadioButtonMenuItem mi = new JRadioButtonMenuItem(action);
            menu.add(mi);
            bg.add(mi);
            if (name.equals(lafId)) {
                mi.setSelected(true);
            }
        }
        return menu;
    }

    @Override
    public void itemStateChanged(ItemEvent e) {
        String componentName = (String) e.getItem();
        changeTableModel(getClassName(componentName));
        selectedItem = componentName;
    }

    private String getClassName(String componentName) {
        if (componentName.equals("TableHeader")) {
            return PACKAGE + "table.JTableHeader";
        } else {
            return PACKAGE + "J" + componentName;
        }
    }

    private void changeTableModel(String className) {
        DefaultTableModel model = models.get(className);
        if (model != null) {
            table.setModel(model);
            return;
        }
        model = new DefaultTableModel(COLUMN_NAMES, 0);
        table.setModel(model);
        models.put(className, model);
        JComponent component = null;
        try {//  Hack so I don't have to sign the jar file for usage in Java Webstart
            if (className.endsWith("JFileChooser")) {
                component = new JFileChooser(new DummyFileSystemView());
            } else {
                Object o = Class.forName(className).newInstance();
                component = (JComponent) o;
            }
        } catch (Exception e) {
            Object[] row = {e.toString(), "", "", ""};
            model.addRow(row);
            return;
        }
        ActionMap actionMap = component.getActionMap();
        Object[] keys = actionMap.allKeys();
        if (keys == null) {
            Object[] row = {"No actions found", "", "", ""};
            model.addRow(row);
            return;
        }
        for (int i = 0; i < keys.length; i++) {
            Object key = keys[i];
            if (key instanceof String) {
                continue;
            } else {
                keys[i] = "";
            }
        }
        Arrays.sort(keys);
        for (int i = 0; i < keys.length; i++) {
            Object key = keys[i];

            if (key != "") {
                Object[] row = {key, "", "", ""};
                model.addRow(row);
            }
        }
        updateModelForInputMap(model, 1, 
                component.getInputMap(JComponent.WHEN_FOCUSED));
        updateModelForInputMap(model, 2, 
                component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW));
        updateModelForInputMap(model, 3, 
                component.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT));
    }

    private void updateModelForInputMap(TableModel model, int column, InputMap inputMap) {
        if (inputMap == null) {
            return;
        }
        KeyStroke[] keys = inputMap.allKeys();
        if (keys == null) {
            return;
        }
        Hashtable<Object, String> actions = new Hashtable<Object, String>(keys.length);
        for (int i = 0; i < keys.length; i++) {
            KeyStroke key = keys[i];
            Object actionName = inputMap.get(key);
            Object value = actions.get(actionName);
            if (value == null) {
                actions.put(actionName, key.toString().replace("pressed ", ""));
            } else {
                actions.put(actionName, value + ", " + key.toString().replace("pressed ", ""));
            }
        }
        for (int i = 0; i < model.getRowCount(); i++) {
            String o = actions.get(model.getValueAt(i, 0));
            if (o != null) {
                model.setValueAt(o.toString(), i, column);
            }
        }
    }

    class ChangeLookAndFeelAction extends AbstractAction {

        private static final long serialVersionUID = 1L;
        private String laf;

        protected ChangeLookAndFeelAction(String laf, String name) {
            this.laf = laf;
            putValue(Action.NAME, name);
            putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            try {
                JMenuItem mi = (JMenuItem) e.getSource();
                JPopupMenu popup = (JPopupMenu) mi.getParent();
                JRootPane rootPane = SwingUtilities.getRootPane(popup.getInvoker());
                Component c = rootPane.getContentPane().getComponent(0);
                rootPane.getContentPane().remove(c);
                UIManager.setLookAndFeel(laf);
                KeyBindings bindings = new KeyBindings();
                rootPane.getContentPane().add(bindings.getContentPane());
                SwingUtilities.updateComponentTreeUI(rootPane);
                rootPane.requestFocusInWindow();
            } catch (Exception ex) {
                System.out.println("Failed loading L&F: " + laf);
                System.out.println(ex);
            }
        }
    }

    class ExitAction extends AbstractAction {

        private static final long serialVersionUID = 1L;

        public ExitAction() {
            putValue(Action.NAME, "Exit");
            putValue(Action.SHORT_DESCRIPTION, getValue(Action.NAME));
            putValue(Action.MNEMONIC_KEY, new Integer(KeyEvent.VK_X));
        }

        @Override
        public void actionPerformed(ActionEvent e) {
            System.exit(0);
        }
    }

    class DummyFileSystemView extends FileSystemView {

        @Override
        public File createNewFolder(File containingDir) {
            return null;
        }

        @Override
        public File getDefaultDirectory() {
            return null;
        }

        @Override
        public File getHomeDirectory() {
            return null;
        }
    }

    private static void createAndShowGUI() {
        KeyBindings application = new KeyBindings();
        JFrame.setDefaultLookAndFeelDecorated(true);
        JFrame frame = new JFrame("Key Bindings");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(application.getMenuBar());
        frame.getContentPane().add(application.getContentPane());
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
        /*try {
            SynthLookAndFeel laf = new SynthLookAndFeel();
            UIManager.setLookAndFeel(laf);
            KeyBindings bindings = new KeyBindings();
        } catch (UnsupportedLookAndFeelException ex) {
            Logger.getLogger(KeyBindings.class.getName()).log(Level.SEVERE, null, ex);
        }   */
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {

                createAndShowGUI();
            }
        });
    }
}