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);
}
}
Related
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.
What I am trying to do is make a button that will end the frame as well as end the program but allow other parts, JOGL in this case, to do their own dispose Functions.
For instance, when I use the standard close button for the JFrame with EXIT_ON_CLOSE it will end the program but allow JOGL to do its clean up. And if I do System.exit(0) it will not allow any clean up from JOGL.
Essentially:
Custom Close JButton ===> Cleanly end application.
How about using WindowAdapter to override the WindowClosing event
this.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent ev) {
//add your logic for closing here
}
});
You could free your resources in the button handler as Quirliom suggested.
But System.exit() is not as abruptly as you assume.
It calls all Shutdown hooks before ending the program.
To dispose your resources, you could add a shutdown hook for JOGL:
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
animator.stop();
frame.dispose();
}
});
Tying your cleanup to a Button Handler or a Window is fine if you know all your exits. A shutdown hook makes sure your cleanup is called, however you exit your application.
Just make sure to keep your shutdown hook clean and simple.
I'm just getting to grips with GUI programming in java. Here is a trivial program (from O'Reilly's "Head First Java") which on the face of it looks easy to understand, but there's an aspect of it which I don't follow.
import javax.swing.*;
public class Test {
public static void main(String[] args) {
JFrame frame=new JFrame();
JButton button = new JButton("click me");
frame.getContentPane().add(button);
frame.setSize(300,300);
frame.setVisible(true);
}
}
This simple program, when compiled and run, will open a window with a button on it.
What I don't understand is what is happening with the flow of execution. When I run this program, the static main method of the Test class runs, all the commands in main() are executed -- so why doesn't the process terminate after the window appears? Why am I still sitting on what looks like an infinite loop? What is looping?
If I add the line
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
then I find the result even more imcomprehensible. Now, of course, the program terminates
once I've closed the window. But again I don't see why. The frame will be on the stack but I don't see where the program flow is and just the existence of something on the stack is not enough to keep the program alive, surely? I'm missing something fundamental which as far as I can see is not covered in the book I'm reading. I am slightly surprised by this -- "Head first Java" has been very good up until now at pointing out subtleties and explaining what is really going on, but doesn't seem to address this point (at least not that I've spotted).
why doesn't the process terminate after the window appears?
Because the Java Virtual Machine exits only after all non-daemon threads have finished. While not apparent, there's in fact two threads in your program: the main thread, and the event dispatching thread, which does everything related to the Swing GUI components. The event dispatching thread keeps going as long as any GUI components are visible.
Actually the program, while it may work, is wrong, because you're creating and accessing Swing components from the main thread. You ought to be doing all GUI work in the event dispatching thread. That is, it should be something like:
public static void main(String[] args) {
EventQueue.invokeLater(new Runnable() {
JFrame frame=new JFrame();
JButton button = new JButton("click me");
frame.getContentPane().add(button);
frame.setSize(300,300);
frame.setVisible(true);
});
}
The Java process terminates when the last non-demon thread dies. Normally there is just one, the main thread. When you display Swing components additional non-demon threads for event dispatching and GUI shotdown are started. Those terminate when the last top-level component gets disposed. In your sample the main thread dies after leaving the main method. You can have a look into the threads with a debugger or jvisualvm from the JDK tools.
The rest of the GUI flow is event driven. When you e.g. click on the frame's close button an event is generated and sent to the appropriate listeners within the event dispatching thread.
Setting JFrame.EXIT_ON_CLOSE as default close operation is like adding a default event listener to the frame. A quite harsh one, it just shuts down the JVM without respect to the rest of the application's state.
What's the programmatic equivalent of clicking the close (x) button in the upper right corner of a JFrame?
There's the dispose() method but that's not the same thing, since a JFrame can be set to do several different things upon closing (not to mention if there's a WindowListener involved)
You tell the component to dispatch an event. In this case, you want it do dispatch a Window Closing event.
private void exit() {
this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
}
When you hit the x on a JFrame, the system can be set to do various things. The default is that the window is simply hidden with setVisible(false) I believe.
You can set a frame to do different things on close--you can have it dispose, hide or call code based on setDefaultCloseOperation. Here are the options:
DO_NOTHING_ON_CLOSE: Don't do anything; require the program to handle the operation in the windowClosing method of a registered WindowListener object.
HIDE_ON_CLOSE: Automatically hide the frame after invoking any registered WindowListener objects.
DISPOSE_ON_CLOSE: Automatically hide and dispose the frame after invoking any registered WindowListener objects.
EXIT_ON_CLOSE: Exit the application using the System exit method. Use this only in applications.
But I think what you are after is setVisible(false).
You have to insert the call into the AWT message queue so all the timing happens correctly, otherwise it will not dispatch the correct event sequence, especially in a multi-threaded program.
public void closeWindow()
{
if(awtWindow_ != null) {
EventQueue.invokeLater(new Runnable() {
public void run() {
awtWindow_.dispatchEvent(new WindowEvent(awtWindow_, WindowEvent.WINDOW_CLOSING));
}
});
}
}
I'm creating an application in Swing using NetBeans. I would like to be able to manipulate some components during its startup (just once), after the window's made visible, for example update a progress bar. To this end, I have the app's main class, called MainWindow:
public class MainWindow extends JFrame
{
public MainWindow()
{
initComponents(); // NetBeans GUI builder-generated function for setting
// up the window components
}
public void Init()
{
loadLabel.setText("Loading....");
loadProgressBar.setValue(20);
doSomething();
loadProgressBar.setValue(40);
doSomething();
loadProgressBar.setValue(80);
doSomething();
loadProgressBar.setValue(100);
loadLabel.setVisible(false);
loadProgressBar.setVisible(false);
}
/* .... */
public static void main(String args[])
{
java.awt.EventQueue.invokeLater(new Runnable()
{
public void run()
{
mainHandle = new MainWindow();
mainHandle.setVisible(true);
mainHandle.Init();
}
});
}
}
The problem is that the effect of the statements for updating the progress bar (or manipulating any other GUI component) within the Init() function can't be observed. If the Init() function is called from within main() as shown above, the window appears, but is empty, the Init() function executes and returns, only afterwards the window draws its contents but any changes made by Init() aren't visible because the window was empty and inactive the whole time. I also tried calling init from the windowOpened() AWT event, which executes after the window is fully drawn, but amazingly putting any statements for manipulating components there seems to have no effect, or rather they are put in a queue, and executed rapidly at some point in succession, so only the effect of the last one (hiding of the elements) can be observed. The only way I managed to get it working was to remove the whole invokeLater(new Runnable()...) mantra and put the new MainWindow(), setVisible(), Init() sequence directly in main(), which I guess is very ugly and breaks the concept of the gui running in a threaded manner. What is the right way to do this? Where do I put code to be executed first thing when the gui is ready to be manipulated, execute the statements once and return control to the main event loop?
I guess at the moment this is working in such a way, that while the Init() function is operating, any operations on the gui components are suspended (the drawing thread isn't separate and waits for Init() to finish before the manipulations are executed). Maybe I should make Init() a new thread... only how and what kind?
Thanks.
You could change the EventQueue.invokeLater() to invokeAndWait(), and move the call to init() out to a second EventQueue.invokeLater() call.
If (as looks to be the case) doSomething() takes a noticable amount of time, a better idea is to move the Init code into the body of a SwingWorker. This could be executed from the MainWindow() constructor or after the setVisible() call in main and is the idiomatic way to have a responsive GUI (in case the user gets bored waiting and wants to quit) and display some visible signs of progress.
See the process and publish methods for details on how to update the progress bar between doSomething() calls.
You may also want to look into ProgressMonitors for another alternative that would deal with the dialog box etc for you.
There are several things you can do:
For windows (such as JFrame or JDialog) you can attach WindowListener and do your manipulations in windowOpened method.
Override addNotify method and do your control manipulations there.
Attach HierarchyListener and do your manipulations whenever displayability of component changed.
Always make sure your do your component manipulations on EDT. Use SwingUtilities.invokeLater for simple UI updates or SwingWorker for long running tasks