Swing开发如何实现仅支持数字小键盘输入、无需点击自动关闭的弹窗?
解决方案
1 核心需求实现(替代JOptionPane的纯小键盘操作方案)
直接自定义模态JDialog,绑定小键盘按键事件即可。模态Dialog弹出后会阻塞父窗口执行,直到用户按键后自动关闭,完全适配仅小键盘操作的场景。
你可以封装为通用工具方法直接调用:
import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.concurrent.atomic.AtomicInteger; // 返回值:1=确认重置,2=取消操作 public static int showNumpadConfirmDialog(JFrame parent) { AtomicInteger result = new AtomicInteger(0); JDialog dialog = new JDialog(parent, "操作确认", true); // true表示模态,阻塞父线程 dialog.setSize(450, 100); dialog.setLocationRelativeTo(parent); dialog.setDefaultCloseOperation(JDialog.DO_NOTHING_ON_CLOSE); // 禁用右上角关闭,强制用户按键操作 JLabel tipLabel = new JLabel("按小键盘1确认重置,按小键盘2取消", SwingConstants.CENTER); tipLabel.setFont(new Font("Tahoma", Font.PLAIN, 25)); dialog.add(tipLabel); // 采用键绑定实现,不受Dialog内部组件焦点影响,稳定性更高 InputMap inputMap = dialog.getRootPane().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW); ActionMap actionMap = dialog.getRootPane().getActionMap(); // 绑定确认按键(兼容普通数字键和小键盘数字键) inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_1, 0), "confirm"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD1, 0), "confirm"); actionMap.put("confirm", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { result.set(1); dialog.dispose(); } }); // 绑定取消按键 inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_2, 0), "cancel"); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_NUMPAD2, 0), "cancel"); actionMap.put("cancel", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { result.set(2); dialog.dispose(); } }); dialog.setVisible(true); // 此处阻塞,直到Dialog关闭才会继续执行 return result.get(); }
你的原有触发逻辑可以直接改成:
KeyListener keyboardEvent = new KeyListener() { @Override public void keyTyped(KeyEvent e) { if (e.getKeyChar() == '1' && !panel2.isVisible()) { int choose = showNumpadConfirmDialog(frame); if (choose == 1) { // 执行重置逻辑 Variables.contador = 0; Label_Contador_Chico.setText(Integer.toString(Variables.contador)); DBConnection.DBInsertar("UPDATE `joy`.`settings` SET `settingscol` = '" + Integer.toString(Variables.contador) + "' WHERE (`idsettings` = 'Contador');"); } } } @Override public void keyPressed(KeyEvent e) {} @Override public void keyReleased(KeyEvent e) {} };
2 解决KeyboardFocusManager监听器残留问题
只需要把你注册的KeyEventDispatcher实例存为变量,绑定Dialog的窗口关闭事件,在Dialog关闭时主动移除监听器即可:
// 先把监听器实例存下来 KeyEventDispatcher dispatcher = new KeyEventDispatcher() { // 你的原有逻辑不变 }; KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(dispatcher); // 给Dialog加窗口关闭监听,销毁时同步移除监听器 dialog.addWindowListener(new WindowAdapter() { @Override public void windowClosed(WindowEvent e) { KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(dispatcher); } });
3 补充2代码返回0的原因
你的逻辑存在本质错误:你是在创建Dialog的瞬间同步调用了dispatchKeyEvent方法,传入的e是之前触发弹出Dialog的那个按键事件(也就是你按小键盘1弹出窗口的事件),此时还没有捕获到用户后续按1/2的操作,自然永远拿不到目标返回值。你没有把自定义的监听类注册到Swing的事件分发体系中,单次调用只能拿到当前传入的事件,不会监听后续的用户输入。
内容的提问来源于stack exchange,提问作者Joaquin Bonifacino
相关产品推荐
相关产品推荐

