2015-04-19 19 views
0

我試圖從另一個類中禁用JComponent,類似於模態對話。就我而言,我從Swing組件中調用JavaFX對話框;更具體地爲FileChooser。例如,因爲showOpenDialog需要javafx.stage.Window作爲參數,所以不能傳遞JComponent如何從另一個類中阻止JComponent?

我試過使用setEnabled(false)setEnabled(true),但是這有一個奇怪的副作用:一旦調用setEnabled(true)JFrame將被最小化。調用setVisible(true)可以解決這個問題,但會導致屏幕「閃爍」,因爲幀會在短時間內消失。

只有當我使用CountDownLatch來等待文件選擇器的返回時纔會出現此問題,這是必要的,否則它將立即返回,我將無法訪問返回值。

這裏是重現這一問題的SSCCE:

public static void main(String[] args) { 
    EventQueue.invokeLater(() -> { 
     JFrame frame = new JFrame("Test"); 
     JButton button = new JButton("Click me!"); 
     JFXPanel jfxPanel = new JFXPanel(); 

     FileChooser fileChooser = new FileChooser(); 
     button.addActionListener(new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent e) { 
       frame.setEnabled(false); 

       CountDownLatch latch = new CountDownLatch(1); 
       Platform.runLater(() -> { 
        fileChooser.showOpenDialog(null); 
        latch.countDown(); 
       }); 

       try { 
        latch.await(); 
       } catch (InterruptedException ex) { 
        ex.printStackTrace(); 
       } 

       frame.setEnabled(true); 
      } 

     }); 
     frame.add(button); 
     frame.setLocationRelativeTo(null); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     frame.pack(); 
     frame.setVisible(true); 
    }); 
} 

是否有其他選項來阻止組件?

+0

你想阻止'JFrame'完全(如無縮放),或者只是阻止與互動其內容? – 3ph3r

+0

我認爲後者就足夠了。 – Veluria

回答

1

我的答案是基於這篇文章https://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html

的想法是,當打開FileChooser我們使用自定義GlassPane,它可以攔截所有的鼠標事件上。這不是理想的解決方案,因爲您仍然可以最小化,最大化並關閉底層JFrame

public class MyGlassPane extends JComponent implements PropertyChangeListener { 
    public MyGlassPane() { 
     CBListener listener = new CBListener(); 
     addMouseListener(listener); 
     addMouseMotionListener(listener); 
    } 

    @Override 
    public void propertyChange(PropertyChangeEvent evt) { 
     setVisible(((Number) evt.getNewValue()).intValue() == 1); 
    } 
} 
public class CBListener extends MouseInputAdapter { 
    public void mouseMoved(MouseEvent e) { 
     consume(e); 
    } 

    public void mouseDragged(MouseEvent e) { 
     consume(e); 
    } 

    public void mouseClicked(MouseEvent e) { 
     consume(e); 
    } 

    public void mouseEntered(MouseEvent e) { 
     consume(e); 
    } 

    public void mouseExited(MouseEvent e) { 
     consume(e); 
    } 

    public void mousePressed(MouseEvent e) { 
     consume(e); 
    } 

    public void mouseReleased(MouseEvent e) { 
     consume(e); 
    } 

    private void consume(MouseEvent e) { 
     e.consume(); 
    } 
} 

有了上面的類,你可以把下面FileChooser fileChooser = new FileChooser();行這樣的代碼:

button.addActionListener(new ActionListener() { 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     frame.firePropertyChange("disabled", 0, 1); 
     Platform.runLater(() -> { 
      fileChooser.showOpenDialog(null); 
      frame.firePropertyChange("disabled", 1, 0); 
     }); 
    } 
}); 

MyGlassPane mgp = new MyGlassPane(); 
frame.setGlassPane(mgp); 
frame.addPropertyChangeListener("disabled", mgp); 
+0

謝謝你的回答。我也在考慮使用玻璃窗格。就像我在文章中提到的那樣,我只是有一個'組件'(所以情況與我的SSCCE中的不同)。我想我可以檢查組件是否是'instanceof RootPaneContainer',在這種情況下,使用玻璃窗格禁用它。 – Veluria