使用 ctrl+w 关闭当前 window

Close current window using ctrl+w

我有一个 Java 程序,它使用了一堆 JFrame 对象。为了方便清理桌面,我想实现可以用Ctrl + w关闭当前焦点window。

我尝试使用键绑定(在任何视图的超类中),其 ActionactionPerformed 方法包含以下内容:

frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));

这很好用——只要我只使用一个 window。它仅在聚焦最后打开的框架时有效,并且仅关闭该框架。


我的问题是:

  1. 为什么键绑定会这样? (我想这是设计使然。)
  2. 如何在不向 KeyListener 添加任何单个组件的情况下为每帧创建键绑定。

Why does the keybinding behaves like this? (I guess it's by design.)

我猜你做错了什么,但没有任何类型的示例代码,不可能知道是什么

How to create a keybinding per frame without adding any single component to a KeyListener

您可以使用多种方法来实现这一目标...

基于全球的解决方案...

一种方法是采用 "global" 方法,使用不依赖于从根解决方案扩展但可应用于几乎任何现有或未来项目的系统。

AWTEventListener

一个解决方案可能是将 AWTEventListener 附加到 Toolkit。这是相当低的级别,让您可以访问系统正在处理的所有关键事件

import java.awt.AWTEvent;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Toolkit;
import java.awt.Window;
import java.awt.event.AWTEventListener;
import java.awt.event.KeyEvent;
import javax.swing.FocusManager;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    private int count = 0;
    private int xPos = 10;
    private int yPos = 10;

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                installKeyboardMonitor();
                for (int index = 0; index < 10; index++) {
                    makeWindow();
                }
            }
        });
    }

    public static void installKeyboardMonitor() {
        Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
            @Override
            public void eventDispatched(AWTEvent event) {
                KeyEvent ke = (KeyEvent) event;
                if (ke.getID() == KeyEvent.KEY_PRESSED) {
                    System.out.println("Pressed");
                    if (ke.getKeyCode() == KeyEvent.VK_W) {
                        System.out.println("W Key");
                        if (ke.isControlDown()) {
                            System.out.println("Control down");
                            Window window = FocusManager.getCurrentManager().getActiveWindow();
                            if (window != null) {
                                window.dispose();
                            }
                        }
                    }
                }
            }
        }, AWTEvent.KEY_EVENT_MASK);
    }

    public void makeWindow() {
        count++;
        JFrame frame = new JFrame("Test " + count);
        frame.setContentPane(new JPanel(new BorderLayout()) {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
        });
        frame.add(new JLabel("Window " + count));
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setLocation(xPos, yPos);
        frame.setVisible(true);
        xPos += 100;
        yPos += 100;
    }

}

KeyEventDispatcher

这比 AWTEventListener 的级别略低,但它只关注 KeyEvent,这使得它更容易管理,但本质上是相同的想法

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.KeyEventDispatcher;
import java.awt.KeyboardFocusManager;
import java.awt.Window;
import java.awt.event.KeyEvent;
import javax.swing.FocusManager;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    private int count = 0;
    private int xPos = 10;
    private int yPos = 10;

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                installKeyboardMonitor();
                for (int index = 0; index < 10; index++) {
                    makeWindow();
                }
            }
        });
    }

    public static void installKeyboardMonitor() {
        KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(new KeyEventDispatcher() {
            @Override
            public boolean dispatchKeyEvent(KeyEvent ke) {
                if (ke.getID() == KeyEvent.KEY_PRESSED) {
                    System.out.println("Pressed");
                    if (ke.getKeyCode() == KeyEvent.VK_W) {
                        System.out.println("W Key");
                        if (ke.isControlDown()) {
                            System.out.println("Control down");
                            Window window = FocusManager.getCurrentManager().getActiveWindow();
                            if (window != null) {
                                window.dispose();
                                return true;
                            }
                        }
                    }
                }
                return false;
            }
        });
    }

    public void makeWindow() {
        count++;
        JFrame frame = new JFrame("Test " + count);
        frame.setContentPane(new JPanel(new BorderLayout()) {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
        });
        frame.add(new JLabel("Window " + count));
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setLocation(xPos, yPos);
        frame.setVisible(true);
        xPos += 100;
        yPos += 100;
    }

}

可配置的解决方案

另一种解决方案是提供基于"configuration" 的解决方案。这类似于拥有基本组件的概念,但可以让您摆脱被锁定在单个扩展点的束缚。

这种方法有点麻烦,因为您实际上需要记住应用到您的应用程序可能创建的每个 window 和对话框。

它只是使用键绑定 API 来注册针对 windows JRootPane 的绑定,但您可以使用几乎任何您知道不会的组件从 window.

中移除
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.Window;
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.JLabel;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    private int count = 0;
    private int xPos = 10;
    private int yPos = 10;

    public Test() {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                for (int index = 0; index < 10; index++) {
                    makeWindow();
                }
            }
        });
    }

    public static void installKeyBindings(JComponent component) {
        InputMap inputMap = component.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
        ActionMap actionMap = component.getActionMap();

        inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_W, KeyEvent.CTRL_DOWN_MASK), "Window.close");
        actionMap.put("Window.close", new AbstractAction() {
            @Override
            public void actionPerformed(ActionEvent e) {
                Window window = SwingUtilities.windowForComponent(component);
                if (window != null) {
                    window.dispose();
                }
            }
        });
    }

    public void makeWindow() {
        count++;
        JFrame frame = new JFrame("Test " + count);
        installKeyBindings(frame.getRootPane());
        frame.setContentPane(new JPanel(new BorderLayout()) {
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
        });
        frame.add(new JLabel("Window " + count));
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setLocation(xPos, yPos);
        frame.setVisible(true);
        xPos += 100;
        yPos += 100;
    }

}

思前想后

这只是三种可能的解决方案。围绕每个解决方案提供一个更可配置的解决方案并不需要太多努力(这样你就可以提供击键),但我会把它留给你