Skip to main content

How to prevent an applet from being silently closed (with unsaved data)

Posted by carcassi on September 27, 2010 at 11:05 AM PDT

It is generally a good idea to ask the user before closing an application without saving the data. If you deploy an applet, the situation is even worse: the user may get distracted, follow some link, forget what he was doing, and close the whole browser without realizing he closed the applet too. Fortunately, it's very simple to tell the browser to display a warning.

Before closing a page for any reason (reload, closing the tab, close the browser, ...), a "modern" browser will call window.onbeforeunload. If you want to alert the user, you simply need to create a javascript function that calls your applet and returns the warning message.

Here is an example. This is an applet with a checkbox and a textfield. Note the two methods isPreventClose() and getPreventCloseMessage(), which define whether the applet needs to block the closing of the page and what message to prompt.

package test.applet;

public class MyApplet extends javax.swing.JApplet {

    @Override
    public void init() {
        try {
            java.awt.EventQueue.invokeAndWait(new Runnable() {
                public void run() {
                    initComponents();
                }
            });
        } catch (Exception ex) {
        }
    }

    // To be called in javascript
    public boolean isPreventClose() {
        return preventClose.isSelected();
    }

    // To be called in javascript
    public String getPreventCloseMessage() {
        return preventCloseMessage.getText();
    }

    private void initComponents() {
        // Unintresting: simply creates the form
        preventClose = new javax.swing.JCheckBox();
        label = new javax.swing.JLabel();
        preventCloseMessage = new javax.swing.JTextField();
        preventClose.setText("Prevent close");
        label.setText("Message: ");
        preventCloseMessage.setText("You have unsaved changes");
        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(preventClose)
                    .addGroup(layout.createSequentialGroup()
                        .addComponent(label)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(preventCloseMessage, javax.swing.GroupLayout.DEFAULT_SIZE, 304, Short.MAX_VALUE)))
                .addContainerGap())
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(preventClose)
                .addGap(7, 7, 7)
                .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(label)
                    .addComponent(preventCloseMessage, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
    }
   
    private javax.swing.JLabel label;
    private javax.swing.JCheckBox preventClose;
    private javax.swing.JTextField preventCloseMessage;

}

And here is the webpage that uses the applet. The important part is the javascript. The first thing is to register the function confirmExit() to the before unload event. The function simply calls the applet (referenced by the id myapplet) to see whether it needs to prevent the closing and what message needs to be displayed.

<html>

<head>
<title>Applet HTML Page</title>
<script type="text/javascript">
  window.onbeforeunload = confirmExit;

  function confirmExit()
  {
    try {
      if (document.myapplet.isPreventClose()) {
        return document.myapplet.getPreventCloseMessage();
      }
    } catch (ex) {
      // Can't access the applet: could be not even loaded
    }
  }
</script>
</head>

<body>
<h1>How to prevent an applet from closing (with unsaved data)</h1>
<p>
<applet id="myapplet" codebase="classes" code="test/applet/MyApplet.class" width="350" height="200">
</applet>
</p>
<p>Enable the check box to prevent the applet from closing. The text in the textbox will be displayed in the pop-up.</p>
</body>

</html>

Note that if the javascript function returns null, the alert message is still displayed: you need to either let the function end with no return statement or return undefined. null and undefined in javascript are two different things.

Related Topics >>