Can't stop JFrame from closing when user hits 'X' in upper right of window

68 Views Asked by At

I'm trying to get a groovy / griffon project to prompt a user before closing the main window. There are numerous examples of this on the web and it seems pretty straightforward: set defaultCloseOperation to DO_NOTHING_ON_CLOSE and then skip the application.shutdown() call.

When I try this, however, the window is still destroyed. I'm new to griffon and this is not my project, so there may be other things I'm missing and was hoping you experts could help.

Below is the beginning of the view creation code:

@ArtifactProviderFor(GriffonView)
class TceView  {
  JFrame mainFrame 
  ...
  masterPage = builder.with {
    def masterApp = application(size: [890, 700], id: 'mainWindow',minimumSize: [890, 700],//[890, 700]
         title: application.configuration['application.title'] + " " + Launcher.version,
         iconImage: imageIcon('/tce_1.png').image,
         iconImages: [imageIcon('/tce_1.png').image,
                      imageIcon('/tce_1.png').image,
                      imageIcon('/tce_1.png').image],
         defaultCloseOperation: WindowConstants.DO_NOTHING_ON_CLOSE,
         windowClosing: { evt ->
             mainFrame = evt.source
             println("In windowClosing")

             // The below is to check to see if our frame is invisible or destroyed.  
             // It turns out that mainFrame is undefined when the timer ticks.
             def timer = new Timer(5000, new ActionListener() {
                 @Override
                 void actionPerformed(ActionEvent e) {
                     mainFrame.setVisible(true)
                 }
             })
             timer.start()

             if (false)
                 application.shutdown()
      }) {
      // all the other code
  }
}

In the above code, if I set the application.shutdown() to run, the program terminates when the 'x' is pressed in the upper right of the window. If the application.shutdown() is skipped, the window closes, but the program is still running when the 'x' is pressed.

Thanks in advance for any help you can provide!

1

There are 1 best solutions below

0
Andres Almiray On

One way to solve this is to use a ShutdownHandler as shown at https://github.com/aalmiray/griffon-examples/tree/master/shutdown

That particular example uses JavaFX and Java but the base code can be translated to Swing and Groovy.

The first thing is to define an implementation of the ShutdownHandler interface like this one

package org.kordamp.griffon.examples.shutdown;

import griffon.core.GriffonApplication;
import griffon.core.ShutdownHandler;
import griffon.core.i18n.MessageSource;
import griffon.core.threading.UIThreadManager;
import javafx.scene.control.Alert;
import javafx.scene.control.ButtonType;

import javax.annotation.Nonnull;
import javax.inject.Inject;
import javax.inject.Named;

public class MyShutdownHandler implements ShutdownHandler {
    private final MessageSource messageSource;
    private final UIThreadManager uiThreadManager;

    @Inject
    public MyShutdownHandler(@Nonnull @Named("applicationMessageSource") MessageSource messageSource, @Nonnull UIThreadManager uiThreadManager) {
        this.messageSource = messageSource;
        this.uiThreadManager = uiThreadManager;
    }

    @Override
    public boolean canShutdown(@Nonnull GriffonApplication application) {
        return uiThreadManager.runInsideUISync(() -> {
            Alert alert = new Alert(Alert.AlertType.CONFIRMATION);
            alert.setTitle(msg(".alert.title"));
            alert.setHeaderText(msg(".alert.header"));
            alert.setContentText(msg(".alert.content"));
            return alert.showAndWait().orElse(ButtonType.CANCEL) != ButtonType.CANCEL;
        });
    }

    private String msg(String key) {
        return messageSource.getMessage(getClass().getName() + key);
    }

    @Override
    public void onShutdown(@Nonnull GriffonApplication application) {
        System.out.println("Saving workspace ...");
    }
}

The ShutdownHandler interface defines 2 methods you must implement

  1. canShutdown() returning true if the shutdown procedure can continue or false to stop it.
  2. onShutdown() perform a particular cleanup when the shutdown procedure is executed.

In your case you my implement the first method with code similar to what you have in the windowClosing handler.

The last bit is registering this shutdown handler with the application, you can do this at anytime you have access to the application instance. You may do it in a controller, or an event handler, or a lifecycle script. The link shown earlier performa this registration using an event handler. Have a look at the ApplicationModule found in that example.