禁用单个 ALT 类型以激活菜单
Disable single ALT type to activate the menu
我正在尝试禁用 ALT 键的默认行为 Windows 当聚焦 JTextArea 并且框架安装了 JMenu 时的外观。默认情况下,菜单会获得键盘焦点,因此您无法继续在那里输入。
我的第一次尝试是通过将键添加到 JTextArea InputMap 来捕获单个 ALT 按键:
//Disable ALT key presses when the textarea is focused
jta.getInputMap(javax.swing.JComponent.WHEN_FOCUSED).put(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ALT, 0, true), "ALTKEY");
jta.getActionMap().put("ALTKEY", new javax.swing.AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
System.out.println("Performed");
}
});
我注意到这在某些第三方 VM 中按预期工作,但在 Oracle 1.8 的最新版本中却没有。0_211
然后我尝试使用 AWT 组件中的关键侦听器并在事件到达其他组件之前使用该事件。
//Disable ALT key presses when the textarea is focused, second attempt
jta.addKeyListener(new java.awt.event.KeyListener(){
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Pressed");
e.consume();
}
}
@Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Released");
e.consume();
}
}
@Override
public void keyTyped(KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Typed");
e.consume();
}
}
});
运气不好。
最后,我尝试更改用于创建菜单快捷方式的键并完全摆脱烦人的 ALT 行为:
//Disable the ALT for the Mnemonic and put CTRL:
int[] ints = {java.awt.event.KeyEvent.CTRL_MASK};
javax.swing.UIManager.put("Menu.shortcutKeys", ints);
这避免了使用带有 ALT 键的快捷键(并且 CTRL 键工作得很好),但没有阻止按一次 ALT 键完成时的标准行为。
将 L&F 更改为其他平台,或者不将其设置为 Windows 可以解决问题,但当然,它会改变整个程序的外观。
我想我做错了什么,但是更改 InputMap 或添加 KeyListeners 为第三方 VM 工作,所以我开始认为这可能是一个错误。
关于如何找到谁在听 ALT 按键并避免它的任何想法?
有没有办法自定义L&F或者看看它的配置是什么?
完整的测试代码如下:
public class JMenubarAltTest extends javax.swing.JFrame{
private static final long serialVersionUID = 1L;
public JMenubarAltTest(){
super();
//Disable the ALT for the Mnemonic and put CTRL key instead:
int[] ints = {java.awt.event.KeyEvent.CTRL_MASK};
javax.swing.UIManager.put("Menu.shortcutKeys", ints);
//Put the platform L&F, in my case I need this to work in Windows
try {
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}
this.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
//Create a random menu with some random items
javax.swing.JMenuBar jmb = new javax.swing.JMenuBar();
javax.swing.JMenu jm1 = new javax.swing.JMenu("menu1");
jm1.setMnemonic(java.awt.event.KeyEvent.VK_M);
jm1.add(new javax.swing.JMenuItem("item1"));
jm1.add(new javax.swing.JMenuItem("item2"));
jm1.add(new javax.swing.JMenuItem("item3"));
javax.swing.JMenu jm2 = new javax.swing.JMenu("menu1");
jm2.setMnemonic(java.awt.event.KeyEvent.VK_E);
jm2.add(new javax.swing.JMenuItem("item1"));
jm2.add(new javax.swing.JMenuItem("item2"));
jm2.add(new javax.swing.JMenuItem("item3"));
jmb.add(jm1);
jmb.add(jm2);
this.setJMenuBar(jmb);
//Get a JTextArea to show what happens with the focus
javax.swing.JTextArea jta = new javax.swing.JTextArea();
//Disable ALT key presses when the textarea is focused
jta.getInputMap(javax.swing.JComponent.WHEN_FOCUSED).put(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ALT, 0, true), "ALTKEY");
jta.getActionMap().put("ALTKEY", new javax.swing.AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
System.out.println("Performed");
}
});
//Disable ALT key presses when the textarea is focused, second attempt
jta.addKeyListener(new java.awt.event.KeyListener(){
@Override
public void keyPressed(java.awt.event.KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Pressed");
e.consume();
}
}
@Override
public void keyReleased(java.awt.event.KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Released");
e.consume();
}
}
@Override
public void keyTyped(java.awt.event.KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Typed");
e.consume();
}
}
});
this.getContentPane().add(jta);
this.pack();
this.setSize(200, 200);
this.setVisible(true);
}
public static void main(java.lang.String[] args){
new JMenubarAltTest();
}
}
不幸的是,Windows L&F 中的 alt 处理器出于某些原因忽略了消耗标志。所以我们需要使用反射API来移除它。
import java.awt.BorderLayout;
import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.lang.reflect.Method;
import java.util.List;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
public class JMenubarAltTest extends javax.swing.JFrame {
private static final long serialVersionUID = 1L;
private KeyEventPostProcessor altPostprocessor;
public JMenubarAltTest() {
super();
// Disable the ALT for the Mnemonic and put CTRL key instead:
int[] ints = {java.awt.event.KeyEvent.CTRL_MASK};
javax.swing.UIManager.put("Menu.shortcutKeys", ints);
// Put the platform L&F, in my case I need this to work in Windows
try {
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| javax.swing.UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}
this.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
// Create a random menu with some random items
javax.swing.JMenuBar jmb = new javax.swing.JMenuBar();
javax.swing.JMenu jm1 = new javax.swing.JMenu("menu1");
jm1.setMnemonic(java.awt.event.KeyEvent.VK_M);
jm1.add(new javax.swing.JMenuItem("item1"));
jm1.add(new javax.swing.JMenuItem("item2"));
jm1.add(new javax.swing.JMenuItem("item3"));
javax.swing.JMenu jm2 = new javax.swing.JMenu("menu1");
jm2.setMnemonic(java.awt.event.KeyEvent.VK_E);
jm2.add(new javax.swing.JMenuItem("item1"));
jm2.add(new javax.swing.JMenuItem("item2"));
jm2.add(new javax.swing.JMenuItem("item3"));
jmb.add(jm1);
jmb.add(jm2);
this.setJMenuBar(jmb);
// Get a JTextArea to show what happens with the focus
javax.swing.JTextArea jta = new javax.swing.JTextArea();
// Disable ALT key presses when the textarea is focused
jta.addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent e) {
addAltPostprocessor();
}
@Override
public void focusGained(FocusEvent e) {
removeAltProcessor();
}
});
this.getContentPane().add(new JScrollPane(jta));
this.getContentPane().add(new JTextField(), BorderLayout.SOUTH);
this.setSize(400, 300);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
// use reflection to remove the Windows L&F ALT processor.
private void removeAltProcessor() {
if (altPostprocessor == null) {
try {
Method method = KeyboardFocusManager.class.getDeclaredMethod("getKeyEventPostProcessors");
method.setAccessible(true);
@SuppressWarnings("unchecked")
List<KeyEventPostProcessor> list =
(List<KeyEventPostProcessor>) method.invoke(KeyboardFocusManager.getCurrentKeyboardFocusManager());
for (KeyEventPostProcessor pp : list) {
if (pp.getClass().getName().contains("WindowsRootPaneUI")) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(pp);
altPostprocessor = pp;
}
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(altPostprocessor);
}
}
private void addAltPostprocessor() {
if (altPostprocessor != null) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(altPostprocessor);
}
}
public static void main(java.lang.String[] args) {
new JMenubarAltTest();
}
}
在此示例中,当文本区域获得焦点时,ALT 处理将被禁用。对于文本字段,alt 处理仍处于启用状态。
我正在尝试禁用 ALT 键的默认行为 Windows 当聚焦 JTextArea 并且框架安装了 JMenu 时的外观。默认情况下,菜单会获得键盘焦点,因此您无法继续在那里输入。
我的第一次尝试是通过将键添加到 JTextArea InputMap 来捕获单个 ALT 按键:
//Disable ALT key presses when the textarea is focused
jta.getInputMap(javax.swing.JComponent.WHEN_FOCUSED).put(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ALT, 0, true), "ALTKEY");
jta.getActionMap().put("ALTKEY", new javax.swing.AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
System.out.println("Performed");
}
});
我注意到这在某些第三方 VM 中按预期工作,但在 Oracle 1.8 的最新版本中却没有。0_211
然后我尝试使用 AWT 组件中的关键侦听器并在事件到达其他组件之前使用该事件。
//Disable ALT key presses when the textarea is focused, second attempt
jta.addKeyListener(new java.awt.event.KeyListener(){
@Override
public void keyPressed(KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Pressed");
e.consume();
}
}
@Override
public void keyReleased(KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Released");
e.consume();
}
}
@Override
public void keyTyped(KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Typed");
e.consume();
}
}
});
运气不好。
最后,我尝试更改用于创建菜单快捷方式的键并完全摆脱烦人的 ALT 行为:
//Disable the ALT for the Mnemonic and put CTRL:
int[] ints = {java.awt.event.KeyEvent.CTRL_MASK};
javax.swing.UIManager.put("Menu.shortcutKeys", ints);
这避免了使用带有 ALT 键的快捷键(并且 CTRL 键工作得很好),但没有阻止按一次 ALT 键完成时的标准行为。
将 L&F 更改为其他平台,或者不将其设置为 Windows 可以解决问题,但当然,它会改变整个程序的外观。
我想我做错了什么,但是更改 InputMap 或添加 KeyListeners 为第三方 VM 工作,所以我开始认为这可能是一个错误。
关于如何找到谁在听 ALT 按键并避免它的任何想法? 有没有办法自定义L&F或者看看它的配置是什么?
完整的测试代码如下:
public class JMenubarAltTest extends javax.swing.JFrame{
private static final long serialVersionUID = 1L;
public JMenubarAltTest(){
super();
//Disable the ALT for the Mnemonic and put CTRL key instead:
int[] ints = {java.awt.event.KeyEvent.CTRL_MASK};
javax.swing.UIManager.put("Menu.shortcutKeys", ints);
//Put the platform L&F, in my case I need this to work in Windows
try {
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | javax.swing.UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}
this.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
//Create a random menu with some random items
javax.swing.JMenuBar jmb = new javax.swing.JMenuBar();
javax.swing.JMenu jm1 = new javax.swing.JMenu("menu1");
jm1.setMnemonic(java.awt.event.KeyEvent.VK_M);
jm1.add(new javax.swing.JMenuItem("item1"));
jm1.add(new javax.swing.JMenuItem("item2"));
jm1.add(new javax.swing.JMenuItem("item3"));
javax.swing.JMenu jm2 = new javax.swing.JMenu("menu1");
jm2.setMnemonic(java.awt.event.KeyEvent.VK_E);
jm2.add(new javax.swing.JMenuItem("item1"));
jm2.add(new javax.swing.JMenuItem("item2"));
jm2.add(new javax.swing.JMenuItem("item3"));
jmb.add(jm1);
jmb.add(jm2);
this.setJMenuBar(jmb);
//Get a JTextArea to show what happens with the focus
javax.swing.JTextArea jta = new javax.swing.JTextArea();
//Disable ALT key presses when the textarea is focused
jta.getInputMap(javax.swing.JComponent.WHEN_FOCUSED).put(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_ALT, 0, true), "ALTKEY");
jta.getActionMap().put("ALTKEY", new javax.swing.AbstractAction() {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(java.awt.event.ActionEvent e) {
System.out.println("Performed");
}
});
//Disable ALT key presses when the textarea is focused, second attempt
jta.addKeyListener(new java.awt.event.KeyListener(){
@Override
public void keyPressed(java.awt.event.KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Pressed");
e.consume();
}
}
@Override
public void keyReleased(java.awt.event.KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Released");
e.consume();
}
}
@Override
public void keyTyped(java.awt.event.KeyEvent e) {
if(e.getKeyCode() == java.awt.event.KeyEvent.VK_ALT){
System.out.println("Typed");
e.consume();
}
}
});
this.getContentPane().add(jta);
this.pack();
this.setSize(200, 200);
this.setVisible(true);
}
public static void main(java.lang.String[] args){
new JMenubarAltTest();
}
}
不幸的是,Windows L&F 中的 alt 处理器出于某些原因忽略了消耗标志。所以我们需要使用反射API来移除它。
import java.awt.BorderLayout;
import java.awt.KeyEventPostProcessor;
import java.awt.KeyboardFocusManager;
import java.awt.event.FocusEvent;
import java.awt.event.FocusListener;
import java.lang.reflect.Method;
import java.util.List;
import javax.swing.JScrollPane;
import javax.swing.JTextField;
public class JMenubarAltTest extends javax.swing.JFrame {
private static final long serialVersionUID = 1L;
private KeyEventPostProcessor altPostprocessor;
public JMenubarAltTest() {
super();
// Disable the ALT for the Mnemonic and put CTRL key instead:
int[] ints = {java.awt.event.KeyEvent.CTRL_MASK};
javax.swing.UIManager.put("Menu.shortcutKeys", ints);
// Put the platform L&F, in my case I need this to work in Windows
try {
javax.swing.UIManager.setLookAndFeel(javax.swing.UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| javax.swing.UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}
this.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);
// Create a random menu with some random items
javax.swing.JMenuBar jmb = new javax.swing.JMenuBar();
javax.swing.JMenu jm1 = new javax.swing.JMenu("menu1");
jm1.setMnemonic(java.awt.event.KeyEvent.VK_M);
jm1.add(new javax.swing.JMenuItem("item1"));
jm1.add(new javax.swing.JMenuItem("item2"));
jm1.add(new javax.swing.JMenuItem("item3"));
javax.swing.JMenu jm2 = new javax.swing.JMenu("menu1");
jm2.setMnemonic(java.awt.event.KeyEvent.VK_E);
jm2.add(new javax.swing.JMenuItem("item1"));
jm2.add(new javax.swing.JMenuItem("item2"));
jm2.add(new javax.swing.JMenuItem("item3"));
jmb.add(jm1);
jmb.add(jm2);
this.setJMenuBar(jmb);
// Get a JTextArea to show what happens with the focus
javax.swing.JTextArea jta = new javax.swing.JTextArea();
// Disable ALT key presses when the textarea is focused
jta.addFocusListener(new FocusListener() {
@Override
public void focusLost(FocusEvent e) {
addAltPostprocessor();
}
@Override
public void focusGained(FocusEvent e) {
removeAltProcessor();
}
});
this.getContentPane().add(new JScrollPane(jta));
this.getContentPane().add(new JTextField(), BorderLayout.SOUTH);
this.setSize(400, 300);
this.setLocationRelativeTo(null);
this.setVisible(true);
}
// use reflection to remove the Windows L&F ALT processor.
private void removeAltProcessor() {
if (altPostprocessor == null) {
try {
Method method = KeyboardFocusManager.class.getDeclaredMethod("getKeyEventPostProcessors");
method.setAccessible(true);
@SuppressWarnings("unchecked")
List<KeyEventPostProcessor> list =
(List<KeyEventPostProcessor>) method.invoke(KeyboardFocusManager.getCurrentKeyboardFocusManager());
for (KeyEventPostProcessor pp : list) {
if (pp.getClass().getName().contains("WindowsRootPaneUI")) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(pp);
altPostprocessor = pp;
}
}
} catch (Exception e) {
e.printStackTrace();
}
} else {
KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventPostProcessor(altPostprocessor);
}
}
private void addAltPostprocessor() {
if (altPostprocessor != null) {
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventPostProcessor(altPostprocessor);
}
}
public static void main(java.lang.String[] args) {
new JMenubarAltTest();
}
}
在此示例中,当文本区域获得焦点时,ALT 处理将被禁用。对于文本字段,alt 处理仍处于启用状态。