Don’t call your main
method from a listener method. This may look like having the desired effect, but will have the main
method running on the event handling thread while the methods invoked for the current event processing are still on the stack. This will not only keep their resources in memory, it will backfire if you ever try to open a GUI again.
Further take care not to close any console related resource (System.in
or System.out
) when opening the GUI, as you can’t re-open them when you want to use the console again.
If I understand you correctly, you have a program flow in your main method that doesn’t follow the event driven flow of a GUI application and you want to return to that program flow. One approach for a simple GUI, is to use a modal dialog instead of a window or frame.
public static void main(String[] args) {
// a simple console application
for(boolean exit = false; !exit; ) {
System.out.println("Enter choice:");
System.out.println("\t1 - Say hello");
System.out.println("\t2 - Open GUI");
System.out.println("\t3 - Exit");
switch(System.console().readLine()) {
case "1": sayHello(); break;
case "2": openGUI(); break;
case "3": exit = true; break;
default: System.out.println("Not a valid input");
}
}
}
private static void sayHello() {
String name = System.console().readLine("Enter your name: ");
System.out.println("Hello "+name);
}
private static void openGUI() { // a temporary GUI application
JDialog d = new JDialog((Window)null, Dialog.ModalityType.TOOLKIT_MODAL);
JButton b = new JButton("Exit GUI");
b.addActionListener(ev -> d.dispose());
d.getContentPane().add(b, BorderLayout.PAGE_END);
d.pack();
d.setVisible(true);
}
For a modal dialog, the method invocation that will open it does not return until it has been closed. The example uses dispose()
to ensure that the resources are released timely and the event handling thread will terminate, so the main method can terminate the program by simply returning, like an ordinary console application.
If a dialog is not an option or a more complex GUI is involved, the logic of letting a GUI run until a certain event will happen, has been generalized with the SecondaryLoop
class:
public static void main(String[] args) {
for(boolean exit = false; !exit; ) {
System.out.println("Enter choice:");
System.out.println("\t1 - Say hello");
System.out.println("\t2 - Open GUI");
System.out.println("\t3 - Exit");
switch(System.console().readLine()) {
case "1": sayHello(); break;
case "2": openGUI(); break;
case "3": exit = true; break;
default: System.out.println("Not a valid input");
}
}
}
private static void sayHello() {
String name = System.console().readLine("Enter your name: ");
System.out.println("Hello "+name);
}
private static void openGUI() {
JFrame d = new JFrame();
SecondaryLoop eventLoop = d.getToolkit().getSystemEventQueue().createSecondaryLoop();
JButton b = new JButton("Exit GUI");
b.addActionListener(ev -> {
d.dispose();
eventLoop.exit();
});
d.getContentPane().add(b, BorderLayout.PAGE_END);
d.pack();
d.setVisible(true);
System.out.println("UI created");
eventLoop.enter();
System.out.println("UI disposed");
}
Since opening the JFrame
does not let the main thread wait, as indicated by the subsequent print statement, this code uses the SecondaryLoop
’s enter()
method, to enter an event processing loop that will only end when the button’s action listener will call the exit()
method. Then, the main thread returns and continues processing the console loop.