Reputation: 7
I learned Java for about 1 year some years ago. Now I wanted to go back to it, but my skills got a bit rusty. So I'm using Eclipse with the WindowBuilder to make an easy Form Application to get started again. I wanted to get a popup window when I exit the application because in future projects I need to execute some code when the application is being exited by another way than my own exit button (for example via the red cross or Alt+F4).
So this is my code so far:
import java.awt.EventQueue;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JButton;
import java.awt.BorderLayout;
import java.awt.event.ActionListener;
import java.awt.event.ActionEvent;
public class Mainframe {
private JFrame frame;
/**
* Launch the application.
*/
public static void main(String[] args) {
Runtime.getRuntime().addShutdownHook(new Thread()
{
@Override
public void run()
{
JOptionPane.showConfirmDialog(null, "Do you", "Message",
JOptionPane.YES_NO_OPTION);
MessageBox.infoBox("YOUR INFORMATION HERE", "TITLE BAR MESSAGE");
}
});
EventQueue.invokeLater(new Runnable() {
public void run() {
try {
Mainframe window = new Mainframe();
window.frame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
/**
* Create the application.
*/
public Mainframe() {
initialize();
}
/**
* Initialize the contents of the frame.
*/
private void initialize() {
frame = new JFrame();
frame.setBounds(100, 100, 450, 300);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JButton btnNewButton = new JButton("New button");
btnNewButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent arg0) {
System.exit(0);
}
});
frame.getContentPane().add(btnNewButton, BorderLayout.SOUTH);
}
}
I used the code for the "when the Application is being exited" from this example, but no matter how I close it, no "Messagebox is appearing". When I use the code for the MessageBoxes directly after the main void, the MessageBoxes appear, so I guess I missplaced the ShutdownHook.
I would really appreciate if anybody can help me fix this problem.
Upvotes: 0
Views: 2349
Reputation: 51
I'm a little late to the party here but figured I'd add my 2 cents. I think it's best to use a static class that allows for shutdown listeners. It's much less complicated, and allows for checking if the JVM is currently shutting down (ex: to hide log messages). Here's the implementation I went with:
import java.time.Duration;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
public enum ShutdownNotifier {
INSTANCE;
private static final Class<?> THIS_CLASS = new Object() {
}.getClass().getEnclosingClass();
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(THIS_CLASS);
private Set<AutoCloseable> _listeners;
private CompletableFuture<Void> _shutdownFuture;
public boolean isShuttingDown() {
return getShutdownFuture().isDone();
}
public boolean addListener(AutoCloseable listener) {
if (listener == null)
return false;
var listeners = this.getListeners();
boolean added;
synchronized (listeners) {
added = listeners.add(listener);
}
if (this.isShuttingDown()) {
this.notifyListeners();
return true;
}
return added;
}
public boolean removeListener(AutoCloseable listener) {
if (listener == null)
return false;
var listeners = getListeners(false);
if (listeners == null)
return false;
synchronized (listeners) {
return listeners.remove(listener);
}
}
private Set<AutoCloseable> getListeners() {
return getListeners(true);
}
private Set<AutoCloseable> getListeners(boolean create) {
if (_listeners == null && create)
synchronized (this) {
if (_listeners == null && create)
_listeners = new HashSet<>();
}
return _listeners;
}
private CompletableFuture<Void> getShutdownFuture() {
if (_shutdownFuture == null)
synchronized (this) {
if (_shutdownFuture == null) {
var future = new CompletableFuture<Void>();
future.whenComplete((v, t) -> {
notifyListeners();
});
try {
Runtime.getRuntime().addShutdownHook(new Thread(() -> future.complete(null)));
} catch (IllegalStateException e) {
future.complete(null);
}
_shutdownFuture = future;
}
}
return _shutdownFuture;
}
private void notifyListeners() {
var listeners = getListeners(false);
if (listeners == null)
return;
while (true) {
AutoCloseable listener;
synchronized (listeners) {
var iter = listeners.iterator();
if (!iter.hasNext())
break;
listener = iter.next();
iter.remove();
}
try {
listener.close();
} catch (Throwable t) {
logger.warn("shutdown listener invocation failed", t);
}
}
}
}
Upvotes: 1
Reputation: 15684
The shutdown hook is meant to perform certain actions (such as closing database connections and shutting down threads) once the application has been shut down (be it by a System.exit
call or a kill signal from the OS). It is not meant to be used for these kinds of dialogs.
You will want to add a WindowListener
to your JFrame
, and perform an action on the windowClosing
and/or windowClosed
events. In this listener, you can then display a dialog or whatever you wish.
If you wish to be able to override the closing of the window, you can find details on how to do so on this question.
Upvotes: 1