GUI application shuts down before the Shutdown Hook message appears - java

Java newbie here. Here's the deal:
I've got the following, simple shutdown-hook:
class SHook implements Runnable {
public void run() {
System.out.println("SH is done.");
}
}
And I've got a GUI application with a TextArea were the output is redirected, so that the message shows up there. Its window listener is again really simple:
public class MyAdapter extends WindowAdapter {
public void windowClosing(WindowEvent w){
System.exit(0);
}
}
As I close the GUI application with the [X] button, the message shows up for a split second before the whole thing shuts down. Nothing wrong here.
What I would like to do is: after the message has been printed, wait for a couple seconds, enough to clearly see that the message has been printed.
Adding a sleep or wait or whatever to the run method doesn't seem to work as the application still closes immediately.
I'm guessing the shutdown-hook is actually doing its job properly, it's just that the application doesn't care and closes the GUI immediately, while my hook prints its message somewhere in the Java limbo.
Is that correct? If yes, is there any simple way to make sure the GUI application only closes after the shutdown-hook is done, without making the shutdown-hook a non-shutdown-hook?

On your JFrame call method:
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
Then make sure that your WindowAdapter is added to JFrame with method adWindowListener.
Then in windowClosing put some println to see when it's called and of course use System.exit(0) in windowClosing if you want frame to be closed.

Related

Saving last window properties/content in javafx

I want to save information from last window (there is possible to use a couple of window in my program) before closing java fx app.
I tried to do this in stop() method, but it saves first opened window.
using Platform.exit() stops whole app after closing randow window.
I tried to do some special main window and let user save chosen window by using extra button, but it's not the prettiest solution.
How can I save last used window? Is there any event handler which is gonna solve my problem?
Yes there is, a few ways you could try...
1) Inside of your Application class, in the Application#launch method, specify the onCloseRequest event
yourStage.setOnCloseRequest(event -> {
//Do Your on close events here
});
2) Inside of your Application class, override the Application#stop method
#Override
public void stop(){
//Do Your on close events here
}
And alternatively, you can specify a system shutdown hook for when the jvm exits, which you can do like so
Runtime.getRuntime().addShutdownHook(() -> whatToDoOnExit());

exit a console application while a Swing JFrame still exists

I would like to exit a console application while a javax.swing.JFrame still exists.
I have a console program that displays a javax.swing.JFrame. Sometimes I want to redirect the standard output to a file.
java -cp path com.domain.package > output.log
One plausible JFrame config value is WindowConstants.DISPOSE_ON_CLOSE and it is my understanding that the JFrame becomes disposed of when it is clicked to close, but the console program blocks at the closing brace of main. I do not know what it is waiting for. At that point I have to Control-C to terminate main.
Another plausible JFrame config value is WindowConstants.EXIT_ON_CLOSE and it is my understanding that when the JFrame is clicked to close, not only does the JFrame close but it also causes main to terminate. Note that even if main has reached the closing brace it does not exit until the click that closes the JFrame. This behaviour is better than the previous case because there is no need to Control-C to terminate main.
I want the console program to terminate so that the output.log file is released even if the JFrame is still alive. I tried to do this by having the JFrame owned by a Runnable in a Thread. That did not work; the console program does not terminate until the JFrame is closed.
// main program...
static void main(String[] args)
{
PlotWorker worker = new PlotWorker(data);
Thread thread = new Thread(worker);
thread.start();
// do not use thread.join
// simply exit at the closing brace of main
}
// owner of the JFrame...
class PlotWorker implements Runnable
{
JFrame jFrame;
#Override
public void run()
{
jFrame = new JFrame();
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
}
Realistically I know I can look at the output.log file with a text editor (or just Linux cat the file from a second console) even if the standard output in the first console still has a "handle" on the output.log. I would prefer a clean solution that exits while the JFrame still exists.
EDIT: This question is no longer important to me. I decided to screen capture and save to disk the JFrame image, thereby obviating the need to keep the JFrame open, then proceed to close the JFrame, thereby closing all files.
EXIT_ON_CLOSE and DISPOSE_ON_CLOSE to my knowledge only govern the application behavior in regards to what happens with the JFrame, I.E. if it's set to exit_on_close, you get a System.exit(0) when the JFrame is closed.
In general, I think System.exit(status) is what you want when terminating your application, this should dispose of any object created by it, release file-locks and close any windows. Might be a little messy if you're using a stream to write to your logfile because that will be terminated too, possibly without calling it's .close() function.

Start a game from within an action listener

I have a Blackjack game that I've made in Java and I want to signal the start of the game by clicking a button. All my action listeners work just fine and all that, but the problem lies in that I can't figure out how to start the game without it running completely within the actionPerformed method. Obviously, a function continuously running within the actionPerformed method will effectively disable the rest of my GUI. Here's a code snippet....
go.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
// START GAME SOMEHOW but must run outside of action listener
}
});
Obviously, a function continuously running within the actionPerformed method will effectively disable the rest of my GUI.
This is a valid observation and shows that you have understand the fundamental rule when working with Swing.
Your game is most likely event driven (correct me if I'm wrong) so the action performed by the button should just set the program in a new state, waiting for further events. This is nothing that should be time consuming, and is typically done directly by the EDT.
Of course, if you want to do a fancy start-new-game animation, that needs to be performed in a separate thread, in which case you simply start the animation thread (I would recommend using a SwingWorker though) from within the actionPerformed method, and then return.
In code, I imagine it would look something like this:
go.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// Remove the menu components
someJPanel.removeAll();
// Show the game table
someJPanel.add(new GamePanel());
someJPanel.revalidate();
someJPanel.repaint();
// done. Wait for further user actions.
}
});
You game should probably start in its own thread and manage that itself (hard to say), but to get you going you could start your game in a new "external" thread, something like this in your actionPerformed:
public void actionPerformed(ActionEvent e) {
Thread thread = new Thread("Game thread") {
public void run() {
startGame(); //or however you start your game
}
};
thread.start();
}
I believe that you want to extend javax.swing.SwingWorker.
The non-ui start-up functionality would run in doInBackground and the done method would be called when it finishes to update the ui.
There's even an example in the javadoc Class Description to update a progressbar with the status of what's happening in start-up.

JFrame disappear behind applet's browser window

My app is a JApplet which opens a JFrame. the applet has a listener and a button, so that if the frame goes behind another window (looses focus), the user can simply click the button to get it to come to the front. frame.toFront(); This works fine.
But initially (in the applet's public void init() {}),
after calling frame.setVisible(true); I call frame.toFront(); to to make sure it starts in front. However, the frame then immediately goes behind the browser. Pressing the button calls it back, though.
I have tried a running a separate thread which repeatedly calls frame.toFront(); But as soon as this stops, the frame goes behind the browser anyways. Only when the button is pressed does it come to the front, and stay in front. Also, having a loop or time continually holding it in front is not a good option, because the user may need or want to have it go behind on purpose.
This "bug" is not present on the Mac (which runs Java 1.5), but on Windows (running 1.6) - including IE, FF, Chrome, Safari, but not Opera (strangely).
Possible cause and fix?
Have you tried setAlwaysOnTop(true) on the frame? I'm not sure however, if this is allowed on frames or windows created from an applet.
The setAlwaysOnTop(true) solves one problem, but create another, namely that now there is no way for the user to actually send the window to the back.
My sollution is a hack:
In the WindowListener attached to the JFrame, place this code:
#Override
public void windowDeactivated(WindowEvent e)
{
if(firstToBack) //firstToBack is an bloolean instance variable initialized to true
{
final JFrame f = frame;
new Thread() { public void run() {
try { Thread.sleep(300); } catch(InterruptedException ie) {}
f.toFront();
}}.start();
firstToBack = false;
}
}
This basically starts a new Thread first time, which waits a little and then calls the JFrame to the front. It only executes once, so the frame doesn't keep coming to the front every time the user sends it to the back. The 300 milliseconds is an arbitrary amount of time and perhaps not even necessary.
Perhaps someone can tell me why this works, but when the same kind of thread was started fron the applet's init() method, the window went to the back anyways, after the thread ended?

Why does my application still run after closing main window?

If I make a JFrame like this
public static void main(String[] args) {
new JFrame().setVisible(true);
}
then after closing the window the appication doesn't stop (I need to kill it).
What is the proper way of showing application's main windows ?
I'd also like to know a reason of a proposed solution.
Thanks in advance.
You should call the setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); in your JFrame.
Example code:
public static void main(String[] args) {
Runnable guiCreator = new Runnable() {
public void run() {
JFrame fenster = new JFrame("Hallo Welt mit Swing");
fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
fenster.setVisible(true);
}
};
SwingUtilities.invokeLater(guiCreator);
}
There's a difference between the application window and the application itself... The window runs in its own thread, and finishing main() will not end the application if other threads are still active. When closing the window you should also make sure to close the application, possibly by calling System.exit(0);
Yuval =8-)
You must dispose the frame, invoking the dispose method in your window listener or using setDefaultCloseOperation. For the argument of the last one, you can use two options:
DISPOSE_ON_CLOSE or EXIT_ON_CLOSE.
DISPOSE_ON_CLOSE only dispose the frame resources.
EXIT_ON_CLOSE disposes the frame resources and then invokes System.exit.
There is no real difference between the two unless you have non daemon threads.
I prefer to use DISPOSE_ON_CLOSE because this way I'm able to notice if I forgot to terminate a thread, because the JVM will stop if there are no more threads running. That's also the reason closing a Frame without disposing will not terminate the application, since Swing creates a thread to handle events that is terminated only when dispose is invoked.
The correct way to do this (unless you're writing a very trivial single-window app, i.e. no other windows or threads etc..) is to catch the windowClosing() event, and then call the dispose(); method of the form.
If your program doesn't completely exit after this, it means you have other non-deamon threads running, and you must stop these as best you see fit depending on your program.
Calling System.exit() or setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); will force stop any other threads (and the whole program), meaning your code is less portable, and force-stopping threads is obviously dangerous (in a programming kind of way).
You can set a window listener to the frame so the program terminates after you close it.
frame.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
}

Categories

Resources