Search code examples
javajavascriptswingjdialogjapplet

Hide JDialog of applet when browser's tab is switched


My question seems to be very much related to How to hide JDialog from JApplet when user switch browser tab? But it does not provide a working solution.

I have developed an applet deployed using JWS/JNLP. It starts with showing "NEW GAME" dialog.

private class NewGameDialog extends CustomDialog implements ActionListener {
    ...
    public NewGameDialog () {
       super(topContainer, "NEW GAME", modalityType);

       System.out.println(topContainer + " " + modalityType);
       //prints JApplet and DOCUMENT_MODAL
    ...

CustomDialog just extends JDialog:

public class CustomDialog extends JDialog implements WindowListener {

    public CustomDialog(Container cont, String title, ModalityType modalityType) {
        super(windowForComponent(cont), title, modalityType);
    }

    public static Window windowForComponent(Component c) {
        if (c instanceof Window) return (Window) c;
        return SwingUtilities.windowForComponent(c);
    }

    ...

This is how JDialog is invoked from a GUI class:

public void requestNewGame () {
    SwingUtilities.invokeLater(new Runnable() {
        @Override
        public void run() {
            NewGameDialog dialog = new NewGameDialog();
            dialog.setVisible(true);
        }
    });
}

enter image description here

I have used different types of modality described in How to Use Modality in Dialogs. The goal is to hide JDialog when user switches to another tab in browser. But none of options does not seems to work. The dialog keeps floating above all tabs.

Please, advice how can I hide the dialog when user moves to another tab and show again once user returns to my applet's tab?


Solution

  • This works on the presumption that the parent component changes location on screen when the tab changes. E.G.

    JDialog.getParent().getLocationOnScreen()
    

    Tested & seen to work in:

    • FireFox 19.0
    • Chrome Version 25.0.1364.97 m

    Fails in:

    • Internet Explorer 8.0.7601.17514

    Using the other Dialog.ModalityType values other than MODELESS either denied access to browser tabs or caused security exceptions.

    import java.awt.*;
    import java.awt.event.*;
    import javax.swing.*;
    
    public class DialogApplet extends JApplet {
    
        @Override
        public void init() {
            Runnable r = new Runnable() {
                @Override
                public void run() {
                    initGUI();
                }
            };
            SwingUtilities.invokeLater(r);
        }
    
        public void initGUI() {
            JButton b = new JButton("Show Dialog");
            ActionListener listener = new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent ae) {
                    showDialog();
                }
            };
            b.addActionListener(listener);
            add(b);
        }
    
        private JDialog d;
        JTextArea output;
        int currentX = -1;
        Timer timer;
    
        public void showDialog() {
            if (d==null) {
                output = new JTextArea(5,20);
                Window w = SwingUtilities.windowForComponent(this);
                d = new JDialog(w, "Dialog", Dialog.ModalityType.MODELESS);
                //Dialog.ModalityType.TOOLKIT_MODAL);  //security
                //Dialog.ModalityType.DOCUMENT_MODAL);
                //Dialog.ModalityType.APPLICATION_MODAL);
                d.add(output, BorderLayout.CENTER);
                ActionListener al = new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent ae) {
                        StringBuilder sb = new StringBuilder();
    
    
                        sb.append("parent location: \t" +
                            d.getParent().getLocation() + "\n");
                        sb.append("parent location - screen: \t" +
                            d.getParent().getLocationOnScreen() + "\n");
    
                        System.out.print(sb.toString());
    
                        output.setText(sb.toString());
                        if (currentX>-1 && 
                            currentX!=d.getParent().getLocationOnScreen().getX() 
                            ) {
                            System.out.println( "Goodbye world!" );
                            d.setVisible(false);
                            timer.stop();
                        }
                    }
                };
                timer = new Timer(1000, al);
                d.pack();
                d.setLocationRelativeTo(d.getParent());
            }
            currentX = (int)d.getParent().getLocationOnScreen().getX();
            timer.start();
            d.setVisible(true);
        }
    }
    

    Java Script

    Perhaps instead look to JS for this. The trick seems to be in detecting the HTML window focus/blur events. E.G. as detailed in answers to:

    Obviously when JS Detects tab change, we would have it call a method in the applet such as tabVisible() or tabHidden() to do the appropriate action with the dialog.