在不使用modal dialog的情况下阻止Swing输入

我想阻止对窗口的输入,但仍然可以移动它。

如果有一个modal dialog类型允许产生它的窗口移动,那么我会很高兴。

假设我有一个窗口打开另一个窗口。 然后第二个窗口打开一个modal dialog,它阻止输入到另外两个窗口(很好),但也锁定这两个窗口(为什么 – Amigas没有这样做:)?)。

我的问题是我可能需要在第一个窗口中以可视方式读取内容以供在对话框中使用,但这可能无法实现,因为第二个窗口已锁定到位,覆盖它。

我想,我几乎用玻璃窗解决了这个问题。 我将下面的类设置为我窗口的根窗格的玻璃窗格,然后当我想要阻止时调用setVisible(true),当我想解锁窗口时调用setVisible(false)。 锁定时,窗口会变灰以指示此情况。

鼠标输入被阻止,除了关闭窗口,现在很好 – 问题是我仍然可以在被阻止的窗口上的组件周围进行选项卡,如果我找到一个可编辑的窗口,我可以使用键盘编辑它,无论我的是什么空KeyListener。

有没有一种简单的方法可以防止玻璃窗格后面的组件获得焦点?

我希望它可以在“InputSink”类本身上完成。

我已经尝试添加自己的自私焦点遍历策略并在可见时请求焦点,但这没有任何效果。

我还尝试了一个我发现添加了FocusListener的示例,如果玻璃窗格可见,其focusLost方法会请求焦点,但这样做太过分了,因为窗口始终保持在前面。

有人知道这两个极端之间的解决方案吗? 这就是我所拥有的:

import java.awt.Color; import java.awt.Component; import java.awt.Container; import java.awt.FocusTraversalPolicy; import java.awt.Graphics; import java.awt.Rectangle; import java.awt.event.KeyAdapter; import java.awt.event.MouseAdapter; import javax.swing.JPanel; public class InputSink extends JPanel { public InputSink() { this(0.2f); //Default opacity. } public InputSink(float alpha) { setOpaque(false); setBackground(new Color(0, 0, 0, alpha)); //Just store it here. addMouseListener(new MouseAdapter() {}); addKeyListener(new KeyAdapter() {}); setFocusTraversalPolicy(new FocusTraversalPolicy() { @Override public Component getLastComponent(Container aContainer) { return InputSink.this; } @Override public Component getFirstComponent(Container aContainer) { return InputSink.this; } @Override public Component getDefaultComponent(Container aContainer) { return InputSink.this; } @Override public Component getComponentBefore(Container aContainer, Component aComponent) { return InputSink.this; } @Override public Component getComponentAfter(Container aContainer, Component aComponent) { return InputSink.this; } }); } public void paintComponent(final Graphics gfx) { //Handle grey-out. gfx.setColor(getBackground()); Rectangle rect = gfx.getClipBounds(); gfx.fillRect(rect.x, rect.y, rect.width, rect.height); } @Override public void setVisible(boolean visible) { super.setVisible(visible); if (visible) requestFocus(); } } 

所以我按照Guillaume Polet的建议使用的版本是

 import java.awt.Color; import java.awt.Component; import java.awt.Graphics; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; import java.awt.Rectangle; import java.awt.event.KeyAdapter; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.SwingUtilities; public class InputSink extends JPanel { KeyEventDispatcher blockingDispatcher = new KeyEventDispatcher() { @Override public boolean dispatchKeyEvent(KeyEvent e) { return InputSink.this == ((JFrame) SwingUtilities.getWindowAncestor((Component) e.getSource())).getGlassPane(); //Consume! } }; public InputSink) { this(0.2f); //Default opacity. } public InputSinkfloat alpha) { setOpaque(false); setBackground(new Color(0, 0, 0, alpha)); //Just store it here. addMouseListener(new MouseAdapter() {}); addKeyListener(new KeyAdapter() {}); } public void paintComponent(final Graphics gfx) { //Handle grey-out. gfx.setColor(getBackground()); Rectangle rect = gfx.getClipBounds(); gfx.fillRect(rect.x, rect.y, rect.width, rect.height); } @Override public void setVisible(boolean visible) { super.setVisible(visible); if (visible) KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(blockingDispatcher); else KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(blockingDispatcher); } } 

谢谢!

您可以将KeyEventDispatcher添加到KeyboardFocusManager以阻止键盘输入。

下面的小演示:

 import java.awt.Color; import java.awt.Graphics; import java.awt.KeyEventDispatcher; import java.awt.KeyboardFocusManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.KeyEvent; import java.awt.event.MouseAdapter; import javax.swing.JButton; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.SwingUtilities; import javax.swing.Timer; public class TestGlassPane { private static final int COUNTDOWN = 10; private static final String CLICK_ME = "Click me"; private static final Color GRAY = new Color(192, 192, 192, 128); private JFrame frame; private JButton button; private Timer timer; private int countdown; private KeyEventDispatcher blockingDispatcher; private static class GrayPanel extends JComponent { @Override protected void paintComponent(Graphics g) { g.setColor(GRAY); g.fillRect(0, 0, getWidth(), getHeight()); } } public TestGlassPane() { blockingDispatcher = new KeyEventDispatcher() { @Override public boolean dispatchKeyEvent(KeyEvent e) { return true; } }; } protected void initUI() { frame = new JFrame(TestGlassPane.class.getSimpleName()); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); button = new JButton(CLICK_ME); button.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { blockUserInput(); } }); GrayPanel glassPane = new GrayPanel(); glassPane.addMouseListener(new MouseAdapter() { }); frame.setGlassPane(glassPane); frame.add(button); frame.setSize(200, 200); frame.setLocationRelativeTo(null); frame.setVisible(true); } protected void blockUserInput() { KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher(blockingDispatcher); frame.getGlassPane().setVisible(true); countdown = COUNTDOWN; timer = new Timer(1000, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { countdown--; if (countdown == 0) { timer.stop(); frame.getGlassPane().setVisible(false); button.setText(CLICK_ME); KeyboardFocusManager.getCurrentKeyboardFocusManager().removeKeyEventDispatcher(blockingDispatcher); } else { button.setText("We will be back in " + countdown + " seconds"); } } }); timer.start(); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new TestGlassPane().initUI(); } }); } } 

通常,可以使用Space键激活该按钮,但您会看到它实际上被阻止了。

因为第二个窗口被锁定到位

JDialog对我来说一直都是“可移动的”(使用windows)。

阻止输入的另一种可能性:

当您显示非modal dialog时,请包含此行

 frame.setEnabled(false); 

还要在对话框中添加一个windowListener,以便关闭时

 frame.setEnabled(true); 

似乎在Windows上运行正常,其他平台未知