Java 在不使用模态对话框的情况下阻止Swing输入
我想阻止窗口的输入,但仍然能够移动它 如果有一个模态对话框类型允许生成它的窗口移动,那么我会很高兴 假设我有一扇打开另一扇窗户的窗户。然后,第二个窗口打开一个模式对话框,该对话框会阻止其他两个窗口的输入(很好),但也会将这两个窗口锁定到位(为什么-Amigas没有这样做:)?) 我的问题是,我可能需要在第一个窗口中直观地阅读一些内容,以便在对话框中使用,但这可能不可能,因为第二个窗口已锁定到位,覆盖了它 我想我已经用玻璃窗解决了这个问题。我将下面的类设置为窗口根窗格的玻璃窗格,然后在需要阻止时调用setVisible(true),在需要解锁窗口时调用setVisible(false)。锁定后,窗口灰显以指示此情况 鼠标输入被阻止,除了关闭窗口,现在还可以-问题是我仍然可以在被阻止的窗口上的组件周围进行制表,如果我得到一个可编辑的窗口,我可以用键盘编辑它,而不管我的KeyListener是空的 有没有一种简单的方法可以防止玻璃窗后面的部件聚焦 我希望它可以在“InputSink”类本身上完成 我尝试添加它自己的自私焦点遍历策略,并在焦点可见时请求焦点,但这没有效果 我还尝试了一个添加了FocusListener的示例,它的focusLost方法在玻璃窗格可见时请求focus,但这太过分了,因为窗口始终位于前面 有人知道介于这两个极端之间的解决方案吗?这就是我所拥有的:Java 在不使用模态对话框的情况下阻止Swing输入,java,swing,focus,Java,Swing,Focus,我想阻止窗口的输入,但仍然能够移动它 如果有一个模态对话框类型允许生成它的窗口移动,那么我会很高兴 假设我有一扇打开另一扇窗户的窗户。然后,第二个窗口打开一个模式对话框,该对话框会阻止其他两个窗口的输入(很好),但也会将这两个窗口锁定到位(为什么-Amigas没有这样做:)?) 我的问题是,我可能需要在第一个窗口中直观地阅读一些内容,以便在对话框中使用,但这可能不可能,因为第二个窗口已锁定到位,覆盖了它 我想我已经用玻璃窗解决了这个问题。我将下面的类设置为窗口根窗格的玻璃窗格,然后在需要阻止时调
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();
}
}
所以我按照纪尧姆·波莱特的建议使用的版本是
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();
}
});
}
}
通常,可以使用空格键激活该按钮,但您会看到它实际上被阻止
因为第二个窗口已锁定到位
JDialog对我来说一直是“可移动的”(使用windows)
阻止输入的另一种可能性:
显示非模态对话框时,请包括此行
frame.setEnabled(false);
还向对话框添加windowListener,以便在关闭时
frame.setEnabled(true);
在windows上似乎可以正常工作,其他平台未知为什么应用程序不能将数据从第一个窗口复制到对话框?我需要做出(人工)决定,并根据我在第一个窗口中可以读取的内容在对话框中输入内容。第二个窗口在它前面,如果它打开一个模式对话框,那么我无法移动第二个窗口或第一个窗口,因此如果我需要的位在第二个窗口后面,我需要关闭对话框,移动第二个窗口,剪切/粘贴,写下或记忆有问题的值,然后再次打开对话框。我理解。将做出(人工)决策所需的信息从第一个窗口复制到对话框中。为什么一个窗口中有两个窗口而不是两个面板?带有一个窗口的两个面板可以解决重叠问题。我猜这将是对右边“相关”下问题的一个答案:“为什么模态对话框是邪恶的?”…吉尔伯特-回答:这就是我们的程序的设置方式。有一个主窗口(第一个窗口),您可以从中开始操作。然后,这些操作在第二个窗口中显示实时进度流程图。当需要输入时,此流程图窗口将打开模式对话框。不幸的是,输入有时依赖于主窗口中的某些内容。如果我添加“frame.setEnabled(!visible);”在我的InputSink上的setVisible(boolean)方法中,框架是将InputSink设置为玻璃面板的JFrame,输入被完全阻止,但在阻止时,窗口也被锁定,因为无法选择移动。。(目前正在Windows 7下进行测试)?如果我使用类似以下内容进行筛选,则此选项有效:
return InputSink.this==((JFrame)SwingUtilities.GetWindow祖先((组件)e.getSource()).getGlassPane()代码>而不是在KeyEventDispatcher中仅返回true(可能隐含在您将其称为演示中!)。