-2

I have a java console application that opens a GUI application that is on a separate class after the user gives a certain input. I want to return back to the console once I close the GUI which is achieved by pressing an "Exit" button that the user has the option to do another task or repeat it. I noticed that killing the system with System.exit(0) kills the whole process. I tried working things with threads but I'm relatively new to this and it doesn't seem to work either. Can someone point me in the right direction? Thanks.

I tried using frame.dispose() as well. It does load up the console and prints out the things as expected on calling the main method on System, but won't allow me to enter another input.

btnExit.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent e) {
     frame.dispose();
     System.main(null);
 }
});

Error message: Exception in thread "AWT-EventQueue-0" java.util.NoSuchElementException: No line found.

Anush Poudel
  • 45
  • 1
  • 9

1 Answers1

4

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.

Holger
  • 285,553
  • 42
  • 434
  • 765