为什么一个 Swing 击键有效而另一个无效?
Why does one Swing keystroke work but not the other?
我正在编写一个带有 JTable 的 Swing 程序;我想使用 control-V 粘贴到 JTable 中,并使用 control-S 保存 JTable 上的信息。
我首先使用 JTable.registerKeyboardAction()
通过 control-V 键注册动作,这很有效,但我注意到它的 javadoc 说它已经过时,新代码应该使用输入映射和动作映射以此目的。
我将它们用于 control-S 键,我也将其映射到 JButton,因此我认为它很容易复制。这是我现在用于创建 JFrame 的代码片段:
private JFrame createMainframe()
{
JFrame frame = new JFrame("VisaExtraction");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String saveFileActionName = "Save";
String pasteActionName = "Paste";
Action saveFileAction = new SaveFileAction(saveFileActionName, frame, tableModel);
Action pasteAction = new PasteAction(pasteActionName, frame, tableModel);
// JButton saveButton = new JButton(saveFileAction);
// saveButton.setMnemonic(KeyEvent.VK_S);
JPanel topPanel = new JPanel();
// topPanel.add(saveButton);
mainTable = new LastColumnChangesWidthJTable(tableModel);
JScrollPane scrollPane = new JScrollPane(mainTable);
// set ctrl-s to the 'saveFile' action
// and ctrl-v to the 'paste' action
InputMap tableInputMap = mainTable.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
KeyStroke saveKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK);
tableInputMap.put(saveKeystroke, saveFileActionName);
KeyStroke pasteKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK);
tableInputMap.put(pasteKeystroke, pasteActionName);
// set the saveFile and paste actions to be executed when invoked.
ActionMap tableActionMap = mainTable.getActionMap();
tableActionMap.put(saveFileActionName, saveFileAction);
tableActionMap.put(pasteActionName, pasteAction);
frame.add(topPanel, BorderLayout.NORTH);
frame.add(scrollPane, BorderLayout.CENTER);
frame.pack();
// register ctrl-v to paste into the JTable
// mainTable.registerKeyboardAction
// ( actionListener -> handlePaste(tableModel, new VisaExtractionListener(tableModel)),
// KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK),
// JComponent.WHEN_IN_FOCUSED_WINDOW
// );
return frame;
}
如您所见,我对 "S" 和 "save" 执行的操作与对 "V" 和 "paste" 执行的操作相同,但是在我启动程序,"control-S" 工作(告诉我没有什么可保存的程度)而 "control-V" 不工作(actionPerformed()
方法中的断点未命中)。
是什么导致了这两者之间的差异?
您的问题可能是由于 JTable 已经在另一个输入映射中使用了 ctrl-V 操作。了解组件有 3 个输入映射,我相信 JComponent.WHEN_FOCUSED
优先于 WHEN_IN_FOCUSED_WINDOW
。
我的 MCVE 用于概念验证。更改下面代码中的注释字段以查看哪个有效:
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Foo {
public static void main(String[] args) {
Integer[][] rowData = {{1, 2}, {3, 4}};
String[] columnNames = {"A", "B"};
JTable table = new JTable(rowData, columnNames);
JScrollPane scrollPane = new JScrollPane(table);
// int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
int condition = JComponent.WHEN_FOCUSED;
InputMap inputMap = table.getInputMap(condition);
ActionMap actionMap = table.getActionMap();
KeyStroke saveKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK);
KeyStroke pasteKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK);
inputMap.put(saveKeystroke, saveKeystroke.toString());
inputMap.put(pasteKeystroke, pasteKeystroke.toString());
actionMap.put(saveKeystroke.toString(), new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("save action");
}
});
actionMap.put(pasteKeystroke.toString(), new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("paste action");
}
});
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
同样,在未来,创建 MCVE 的努力应该是你的,因为你是寻求帮助的人。
编辑:我错了。 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
地图是已经在使用中并让您感到困惑的输入地图。在我的 MCVE 更新中,control-V 键有一个非空键字符串:
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Foo {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createGui());
}
public static void createGui() {
Integer[][] rowData = { { 1, 2 }, { 3, 4 } };
String[] columnNames = { "A", "B" };
JTable table = new JTable(rowData, columnNames);
JScrollPane scrollPane = new JScrollPane(table);
int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
// int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
// int condition = JComponent.WHEN_FOCUSED;
InputMap inputMap = table.getInputMap(condition);
ActionMap actionMap = table.getActionMap();
KeyStroke saveKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK);
KeyStroke pasteKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK);
String pasteKey = (String) inputMap.get(pasteKeystroke);
System.out.println(pasteKey);
inputMap.put(saveKeystroke, saveKeystroke.toString());
inputMap.put(pasteKeystroke, pasteKeystroke.toString());
actionMap.put(saveKeystroke.toString(), new MyAction("Save Action"));
actionMap.put(pasteKeystroke.toString(), new MyAction("Paste Action"));
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
@SuppressWarnings("serial")
class MyAction extends AbstractAction {
private String text;
public MyAction(String text) {
this.text = text;
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(text);
}
}
我正在编写一个带有 JTable 的 Swing 程序;我想使用 control-V 粘贴到 JTable 中,并使用 control-S 保存 JTable 上的信息。
我首先使用 JTable.registerKeyboardAction()
通过 control-V 键注册动作,这很有效,但我注意到它的 javadoc 说它已经过时,新代码应该使用输入映射和动作映射以此目的。
我将它们用于 control-S 键,我也将其映射到 JButton,因此我认为它很容易复制。这是我现在用于创建 JFrame 的代码片段:
private JFrame createMainframe()
{
JFrame frame = new JFrame("VisaExtraction");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
String saveFileActionName = "Save";
String pasteActionName = "Paste";
Action saveFileAction = new SaveFileAction(saveFileActionName, frame, tableModel);
Action pasteAction = new PasteAction(pasteActionName, frame, tableModel);
// JButton saveButton = new JButton(saveFileAction);
// saveButton.setMnemonic(KeyEvent.VK_S);
JPanel topPanel = new JPanel();
// topPanel.add(saveButton);
mainTable = new LastColumnChangesWidthJTable(tableModel);
JScrollPane scrollPane = new JScrollPane(mainTable);
// set ctrl-s to the 'saveFile' action
// and ctrl-v to the 'paste' action
InputMap tableInputMap = mainTable.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
KeyStroke saveKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK);
tableInputMap.put(saveKeystroke, saveFileActionName);
KeyStroke pasteKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK);
tableInputMap.put(pasteKeystroke, pasteActionName);
// set the saveFile and paste actions to be executed when invoked.
ActionMap tableActionMap = mainTable.getActionMap();
tableActionMap.put(saveFileActionName, saveFileAction);
tableActionMap.put(pasteActionName, pasteAction);
frame.add(topPanel, BorderLayout.NORTH);
frame.add(scrollPane, BorderLayout.CENTER);
frame.pack();
// register ctrl-v to paste into the JTable
// mainTable.registerKeyboardAction
// ( actionListener -> handlePaste(tableModel, new VisaExtractionListener(tableModel)),
// KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK),
// JComponent.WHEN_IN_FOCUSED_WINDOW
// );
return frame;
}
如您所见,我对 "S" 和 "save" 执行的操作与对 "V" 和 "paste" 执行的操作相同,但是在我启动程序,"control-S" 工作(告诉我没有什么可保存的程度)而 "control-V" 不工作(actionPerformed()
方法中的断点未命中)。
是什么导致了这两者之间的差异?
您的问题可能是由于 JTable 已经在另一个输入映射中使用了 ctrl-V 操作。了解组件有 3 个输入映射,我相信 JComponent.WHEN_FOCUSED
优先于 WHEN_IN_FOCUSED_WINDOW
。
我的 MCVE 用于概念验证。更改下面代码中的注释字段以查看哪个有效:
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Foo {
public static void main(String[] args) {
Integer[][] rowData = {{1, 2}, {3, 4}};
String[] columnNames = {"A", "B"};
JTable table = new JTable(rowData, columnNames);
JScrollPane scrollPane = new JScrollPane(table);
// int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
int condition = JComponent.WHEN_FOCUSED;
InputMap inputMap = table.getInputMap(condition);
ActionMap actionMap = table.getActionMap();
KeyStroke saveKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK);
KeyStroke pasteKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK);
inputMap.put(saveKeystroke, saveKeystroke.toString());
inputMap.put(pasteKeystroke, pasteKeystroke.toString());
actionMap.put(saveKeystroke.toString(), new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("save action");
}
});
actionMap.put(pasteKeystroke.toString(), new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("paste action");
}
});
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
同样,在未来,创建 MCVE 的努力应该是你的,因为你是寻求帮助的人。
编辑:我错了。 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT
地图是已经在使用中并让您感到困惑的输入地图。在我的 MCVE 更新中,control-V 键有一个非空键字符串:
import java.awt.event.ActionEvent;
import java.awt.event.InputEvent;
import java.awt.event.KeyEvent;
import javax.swing.*;
public class Foo {
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> createGui());
}
public static void createGui() {
Integer[][] rowData = { { 1, 2 }, { 3, 4 } };
String[] columnNames = { "A", "B" };
JTable table = new JTable(rowData, columnNames);
JScrollPane scrollPane = new JScrollPane(table);
int condition = JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT;
// int condition = JComponent.WHEN_IN_FOCUSED_WINDOW;
// int condition = JComponent.WHEN_FOCUSED;
InputMap inputMap = table.getInputMap(condition);
ActionMap actionMap = table.getActionMap();
KeyStroke saveKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_S, InputEvent.CTRL_DOWN_MASK);
KeyStroke pasteKeystroke = KeyStroke.getKeyStroke(KeyEvent.VK_V, InputEvent.CTRL_DOWN_MASK);
String pasteKey = (String) inputMap.get(pasteKeystroke);
System.out.println(pasteKey);
inputMap.put(saveKeystroke, saveKeystroke.toString());
inputMap.put(pasteKeystroke, pasteKeystroke.toString());
actionMap.put(saveKeystroke.toString(), new MyAction("Save Action"));
actionMap.put(pasteKeystroke.toString(), new MyAction("Paste Action"));
JFrame frame = new JFrame("Foo");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.add(scrollPane);
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
@SuppressWarnings("serial")
class MyAction extends AbstractAction {
private String text;
public MyAction(String text) {
this.text = text;
}
@Override
public void actionPerformed(ActionEvent e) {
System.out.println(text);
}
}