2015-04-19 18 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