2013-01-17 25 views
2

我想阻止輸入到窗口,但仍然可以移動它。不使用模態對話框阻止Swing輸入

如果有一個模式對話框類型允許產生它移動的窗口,那麼我會很高興。

說我有一個窗口打開另一個窗口。這第二個窗口然後打開一個模式對話框,阻止輸入到其他兩個窗口(罰款),但也鎖定這兩個窗口到位(爲什麼 - 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(); 
} 

} 

所以我用以下紀堯姆波萊的建議的版本是

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); 
} 

} 

謝謝!

+0

爲什麼你的應用程序無法運行將數據從第一個窗口複製到對話框? –

+0

我需要做出(人類)決定,並根據我可以在第一個窗口中讀取的內容在對話框中輸入內容。第二個窗口在它的前面,如果它打開一個模式對話框,那麼我不能移動第二個窗口或第一個窗口,所以如果我需要的位在第二個窗口的後面,我需要關閉對話框,將第二個窗口窗口,剪切/粘貼,記下或記憶有問題的值,然後再次打開對話框。 – nsandersen

+0

我明白了。將您需要的信息複製到第一個窗口(人類)決定的對話框中。爲什麼在一個窗口內有2個窗口而不是2個面板?有一個窗口的兩個面板可以解決重疊問題。 –

回答

2

您可以添加一個KeyEventDispatcherKeyboardFocusManager阻止鍵盤輸入。

小下面演示:

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(); 
      } 
     }); 
    } 

} 

通常情況下,該按鈕可以用空間密鑰激活,但你會看到,它實際上被阻止。

+0

+1好方法 –

+0

這個工程,如果我過濾像這樣的東西:'返回InputSink.this ==((JFrame)SwingUtilities.getWindowAncestor((Component)e.getSource()))。getGlassPane();'而不是隻是返回在KeyEventDispatcher中爲true(可能隱含在您稱之爲演示!)中。 – nsandersen

0

,因爲第二個窗口被鎖定到位

中的JDialog一直是我的 '移動'(使用Windows)。

另一種可能阻止輸入:

當你告訴你的無模式對話框

,包括該行

frame.setEnabled(false); 

還添加了一個的WindowListener到對話框,以便在關閉

frame.setEnabled(true); 

似乎可以在Windows上運行,其他平臺未知

+0

如果我添加\t'frame.setEnabled(!visible);'在我的InputSink的setVisible(boolean)方法中,並且該框架是InputSink被設置爲玻璃面板的JFrame,輸入被完全阻止,_but_阻塞時,窗口也被鎖定,因爲它不能被選擇用於移動..(目前正在Windows 7下測試)? – nsandersen