JMenuItem и клавиша ENTER отпущены
У меня есть JMenuItem
и я хочу получить пользовательский ввод. Пользователь должен иметь возможность запускать функциональность элемента с помощью мыши или клавиатуры.
Функциональность предмета содержит JDialog
быть открытым. Этот диалог прослушивает отпущенные клавиши ENTER и запускает свою собственную функцию при отпускании ENTER.
Когда пользователь нажимает JMenuItem
с помощью клавиши ENTER (нажатая клавиша) он откроет диалоговое окно. Когда он отпускает ENTER, он - и в этом проблема - заставляет запускать диалог. (Когда пользователь отпускает клавишу ВВОДА, он запускает событие для теперь открытого JDialog
, Я не хочу этого Я хочу два отдельных шага: 1-й: Выберите JMenuItem
с помощью ENTER (полный ход или ENTER выпущены), 2-й: Запуск новой функциональности в JDialog с использованием ENTER (полный ход или ENTER выпущены).
До сих пор я пробовал несколько вещей, но я не могу получить JMenuItem
получать ключевые события. Похоже, это некий вопрос, который я не могу обойти до сих пор.
Как можно решить эту проблему?
Если объяснение было немного запутанным, его можно резюмировать так:
я хочу
JMenuItem
чтобы получать события ENTER-key-Release-Events и реагировать на него, я не хочу, чтобы он реагировал на события ENTER-Key-Press-Events.
Небольшой пример кода может показать мою проблему:
редактировать
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
public class MenuItemProblem {
public static void openDialog(JFrame frame){
Action enterReleasedAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
// This action shall be triggered by releasing
// the enter key in the JDialog.
// (There are two times events of the released enter key shall be
// evaluated during the application runs, of which this is the second one.)
// But: It is triggered by the first release of enter in the application,
// which is the one to choose the menu item.
System.out.println("Dialog: Enter was released!");
}
};
JDialog dialog = new JDialog(frame, "My dialog", true);
JRootPane rootPane = dialog.getRootPane();
ActionMap actionMap = rootPane.getActionMap();
String enterReleased = "my_enter_released_function";
actionMap.put(enterReleased, enterReleasedAction);
InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
// Keystroke for releasing the enter key
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, true), enterReleased);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setMinimumSize(new Dimension(260, 300));
dialog.setResizable(true);
dialog.pack();
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
public static void main(String[] args) {
JFrame frame = new JFrame("My App");
JMenuItem item = new JMenuItem("My item");
item.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
// By releasing enter (and mouse clicks, space and so on)
// this action shall be triggered.
// It shall not be triggered by enter key pressed,
// for this would cause the action of the called dialog
// do be triggered.
// But: It is triggered by enter pressed!
// (There are two times events of the released enter key shall be
// evaluated during the application runs, of which this is the first one.)
System.out.println("Choosing the menu item");
openDialog(frame);
}
});
JMenu menu = new JMenu("My menu");
menu.add(item);
JMenuBar bar = new JMenuBar();
bar.add(menu);
// Register alt key to be caught
Action altAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
MenuElement[] elements = MenuSelectionManager.defaultManager().getSelectedPath();
if(elements.length > 0){
MenuSelectionManager.defaultManager().clearSelectedPath();
} else{
menu.doClick();
}
}
};
JRootPane rootPane = frame.getRootPane();
ActionMap actionMap = rootPane.getActionMap();
String altActionKey = "alt_key_for_menu";
actionMap.put(altActionKey, altAction);
InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_ALT, 0, true);
inputMap.put(ks, altActionKey);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(bar);
frame.setSize(350, 250);
frame.setVisible(true);
}
}
Да, я был бы счастлив, если бы вы, ребята, могли указать мне правильное направление. Заранее спасибо и признательность за все ваши усилия!
1 ответ
Хорошо, проблема решена. Я не пытался адаптировать API, но вместо этого адаптировал способ запуска диалогового окна. Подробно я изменил триггер с ENTER, выпущенного на тип ВВОД. Пример кода, чтобы понять, что я сделал:
import java.awt.Dimension;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JRootPane;
import javax.swing.KeyStroke;
import javax.swing.MenuElement;
import javax.swing.MenuSelectionManager;
public class MenuItemSolution {
public static void openDialog(JFrame frame){
Action enterTypedAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("Dialog: Enter was typed!");
}
};
JDialog dialog = new JDialog(frame, "My dialog", true);
JRootPane rootPane = dialog.getRootPane();
ActionMap actionMap = rootPane.getActionMap();
String enterTyped = "my_enter_typed_function";
actionMap.put(enterTyped, enterTypedAction);
InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
// This is the point of change: I just created a KeyStroke to
// deal with ENTER key typed instead of ENTER key released.
// Only problem left (which doesn't matter in my use case):
// Key typed events can occur several time when holding down the ENTER key.
inputMap.put(KeyStroke.getKeyStroke('\n'), enterTyped);
dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
dialog.setMinimumSize(new Dimension(260, 300));
dialog.setResizable(true);
dialog.pack();
dialog.setLocationRelativeTo(frame);
dialog.setVisible(true);
}
public static void main(String[] args) {
JFrame frame = new JFrame("My App");
JMenuItem item = new JMenuItem("My item");
item.addActionListener((ActionEvent e) -> {
openDialog(frame);
});
JMenu menu = new JMenu("My menu");
menu.add(item);
JMenuBar bar = new JMenuBar();
bar.add(menu);
// Register alt key to be caught
Action altAction = new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
MenuElement[] elements = MenuSelectionManager.defaultManager().getSelectedPath();
if(elements.length > 0){
MenuSelectionManager.defaultManager().clearSelectedPath();
} else{
menu.doClick();
}
}
};
JRootPane rootPane = frame.getRootPane();
ActionMap actionMap = rootPane.getActionMap();
String altActionKey = "alt_key_for_menu";
actionMap.put(altActionKey, altAction);
InputMap inputMap = rootPane.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_ALT, 0, true);
inputMap.put(ks, altActionKey);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setJMenuBar(bar);
frame.setSize(350, 250);
frame.setVisible(true);
}
}
Спасибо всем за внимание, особенно @MadProgrammer и @mKorbel!
РЕДАКТИРОВАТЬ
Есть некоторые даже лучшие способы для этого, насколько я знаю, признанные.
1-й подход:
Установите таймер, чтобы реагировать на ENTER
Ключ отпущенных событий во вновь открытом диалоге.
2-й подход:
Принудить ENTER
событие нажатия клавиши во вновь открытом диалоге перед ENTER
обработанное ключом событие обрабатывается.