JTable Key Bindings

java, jtable, key-bindings, swing

Solution

Like @Guillaume, I had no problem running your code. You might look for a `CellEditor` that inadvertently defeats `editingStopped()`, discussed here. An sscce may help clarify the problem.

Addendum: You can cancel editing in the `saveAction()` handler, as shown below.

table.editingCanceled(null);

For reference, I've updated your example in several respects:

- Control-S is not bound to any `JTable` `Action` in common Look & Feel implementations, so there's no need to remove it.

- For cross-platform convenience, use `getMenuShortcutKeyMask()`.

- Swing GUI objects should be constructed and manipulated only on the event dispatch thread.

Code:

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;

public class TestTableKeyBinding extends JFrame {

    private static final int MASK =
        Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
    private JTable table;

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

            @Override
            public void run() {
                TestTableKeyBinding test = new TestTableKeyBinding();
                test.setVisible(true);
            }
        });
    }

    TestTableKeyBinding() {
        super();
        initUI();
        addKeyBindings();
    }

    private void initUI() {
        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        String[] headers = new String[]{"apples", "bananas"};
        String[][] data = new String[][]{{"1", "2"}, {"4", "6"}};
        table = new JTable(data, headers);
        table.setCellSelectionEnabled(true);
        this.add(new JScrollPane(table));
        this.pack();
        this.setSize(new Dimension(300, 400));

    }

    private void addKeyBindings() {
        //root maps
        InputMap im = this.getRootPane().getInputMap(
            JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
        ActionMap am = this.getRootPane().getActionMap();
        //add custom action
        im.put(KeyStroke.getKeyStroke(KeyEvent.VK_S, MASK), "save");
        am.put("save", saveAction());
    }

    private AbstractAction saveAction() {
        AbstractAction save = new AbstractAction() {

            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(
                    TestTableKeyBinding.this.table, "Action Triggered.");
                table.editingCanceled(null);
            }
        };
        return save;
    }
}

Problem

I want to trigger an save action anywhere in my application (Control+S). I've added the necessary key binding, and the action triggers as expected. However, if I try Control+S on a JTable the table starts my custom action and activates the table cell for editing. I think I've disabled the edit action in the table's input map. What am I missing here? ``` import java.awt.Dimension; import java.awt.event.ActionEvent; import javax.swing.AbstractAction; import javax.swing.ActionMap; import javax.swing.InputMap; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JOptionPane; import javax.swing.JScrollPane; import javax.swing.JTable; import javax.swing.KeyStroke; import javax.swing.UIManager; public class TestTableKeyBinding extends JFrame{ JTable table; JScrollPane scroll; public static void main(String[] args){ TestTableKeyBinding test = new TestTableKeyBinding(); test.setVisible(true); } TestTableKeyBinding(){ super(); initUI(); addKeyBindings(); } void initUI(){ this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); String[] headers = new String[]{"apples", "bananas"}; String[][] data = new String[][]{{"1", "2"},{"4","6"}}; table = new JTable(data, headers); table.setCellSelectionEnabled(true); scroll = new JScrollPane(); scroll.setViewportView(table); this.add(scroll); this.pack(); this.setSize(new Dimension(300, 400)); } void addKeyBindings(){ //root maps InputMap im = this.getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); ActionMap am = this.getRootPane().getActionMap(); //add custom action im.put(KeyStroke.getKeyStroke("control S"), "save"); am.put("save", saveAction()); //disable table actions via 'none' table.getInputMap().put(KeyStroke.getKeyStroke("control S"), "none"); table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT).put(KeyStroke.getKeyStroke("control S"), "none"); table.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke("control S"), "none"); table.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("control S"), "none"); ((InputMap)UIManager.get("Table.ancestorInputMap")).put(KeyStroke.getKeyStroke("control S"), "none"); } AbstractAction saveAction(){ AbstractAction save = new AbstractAction(){ public void actionPerformed(ActionEvent e) { // TODO Auto-generated method stub JOptionPane.showMessageDialog(TestTableKeyBinding.this.table, "Action Triggered."); } }; return save; } } ```

Original source

Related problems