简体   繁体   English

如何阻止另一个类的JComponent?

[英]How can I block a JComponent from another class?

I am trying to disable a JComponent from another class, similar to a modal dialogue. 我试图从另一个类禁用JComponent ,类似于模式对话框。 In my case, I'm invoking a JavaFX dialogue from a Swing component; 就我而言,我正在从Swing组件调用JavaFX对话。 more specifically a FileChooser . 更具体地说是FileChooser Since, for example, showOpenDialog expects an javafx.stage.Window as argument, passing the JComponent is not an option. 例如,由于showOpenDialog希望将javafx.stage.Window作为参数,因此不能选择传递JComponent

I tried using setEnabled(false) and setEnabled(true) , but this has a strange side effect: Upon invoking setEnabled(true) , the JFrame will be minimized. 我尝试使用setEnabled(false)setEnabled(true) ,但这有一个奇怪的副作用:调用setEnabled(true)JFrame将被最小化。 Invoking setVisible(true) solves this but causes the screen to “flash”, because the frame will still disappear for a short time. 调用setVisible(true)可以解决此问题,但会导致屏幕“闪烁”,因为框架仍会在短时间内消失。

The problem only occurs when I'm using a CountDownLatch to await the return of the file chooser, which is necessary because otherwise it would return immediately and I wouldn't be able to access the return value. 仅当我使用CountDownLatch等待文件选择器的返回时,才会发生此问题,这是必需的,因为否则它将立即返回,并且我将无法访问返回值。

Here is a SSCCE to reproduce the issue: 这是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);
    });
}

Is there another option to block the component? 还有其他阻止组件的选项吗?

My answer is based on this article https://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html 我的答案基于本文https://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html

The idea is that when FileChooser is opened we use custom GlassPane that intercepts all mouse events. 这个想法是,当FileChooser打开时,我们使用自定义的GlassPane来拦截所有鼠标事件。 It's not ideal solution, because you can still minimize, maximize and close underlying JFrame . 这不是理想的解决方案,因为您仍然可以最小化,最大化和关闭底层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();
    }
}

With above classes you can put below FileChooser fileChooser = new FileChooser(); 通过上述类,您可以在FileChooser fileChooser = new FileChooser(); line code like this: 像这样的行代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM