【问题标题】:How can I block a JComponent from another class?如何阻止另一个类的 JComponent?
【发布时间】:2015-04-19 16:40:55
【问题描述】:

我正在尝试禁用另一个类的JComponent,类似于模态对话。就我而言,我正在从 Swing 组件调用 JavaFX 对话;更具体地说是FileChooser。例如,因为showOpenDialog 需要javafx.stage.Window 作为参数,所以传递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);
    });
}

是否有其他选项可以阻止该组件?

【问题讨论】:

  • 您要完全阻止JFrame(例如不缩放)还是仅仅阻止与其内容的交互?
  • 我认为后者就足够了。

标签: java swing javafx jcomponent filechooser


【解决方案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);

【讨论】:

  • 感谢您的回答。我也在考虑使用玻璃板。问题是,正如我在帖子中提到的,我只有一个 Component(所以情况与我的 SSCCE 中的情况不同)。我想我可以检查该组件是否为instanceof RootPaneContainer,在这种情况下,使用玻璃窗格将其禁用。
猜你喜欢
  • 1970-01-01
  • 2023-04-06
  • 2011-10-18
  • 2013-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多