2015-04-19 3 views
0

Я пытаюсь отключить JComponent из другого класса, похожего на модальный диалог. В моем случае я вызываю диалог JavaFX от компонента Swing; более конкретно, 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