0

How would I go about closing a JFrame based on an ActionEvent from a button click within a JPanel?

I have a total of three classes:

  • Application: contains the main method and runs the program by creating a FrameStartUp object.
  • FrameStartUp: extends the JFrame class and displays the contents within StartUpPanel.
  • StartUpPanel: extends the JPanel class and has all the components and ActionEvents.

Within the StartUpPanel class, I have a button with an ActionEventListener waiting for the button to be clicked.

When the button is clicked I want the application to shut down completely. I know of a method called .dispose() for the JFrame class, but I can't use it because creating an object of FrameStartUp would just run another GUI (run by the constructor).

As I am new to programming and swing, I do not know any other way to fix this, other than getting rid of the StartUpPanel and just creating a JPanel within the FrameStartUp class.

Are there any methods provided by Swing that can access the current JFrame that the panel is on, so the program can close when the ActionEvent is triggered?

Frakcool
  • 10,915
  • 9
  • 50
  • 89
  • 1
    See [The use of multiple JFrames, Good / Bad practice?](https://stackoverflow.com/questions/9554636/the-use-of-multiple-jframes-good-or-bad-practice) (bad), it creates a terrible UX, your task bar could be filled with multiple windows and confuse your user. You could use `JPanels` and `Dialogs` instead or use [Card Layout](https://docs.oracle.com/javase/tutorial/uiswing/layout/card.html). For better help sooner post a proper [mre] – Frakcool Apr 27 '21 at 18:47
  • `System.exit(0);` – isaace Apr 27 '21 at 18:53

1 Answers1

0

I know of a method called .dispose() for the JFrame class

This will work if you explicitly set setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

Are there any methods provided by Swing that can access the current JFrame that the panel is on

Yes... SwingUtilities provides one called getWindowAncestor().

button.addActionListener(e -> {
   SwingUtilities.getWindowAncestor((Component)e.getSource()).dispose();
});

... or more commonly, you can chose to reference a final variable to achieve the same effect...

final JFrame swingStuff = this; // or expose via a getter/setter
button.addActionListener(e -> {
   swingStuff.dispose();
}); 

... however the final variable placement and setter/getter would need a small reproducible code example.

And finally, as others have mentioned, System.exit(0) works quite fantastically well too, so as long as it doesn't break the lifecycle of any of your other components.

My test class:

import javax.swing.*;
import java.awt.*;

public class SwingStuff extends JFrame {
    // Our main JFrame
    public SwingStuff() {
        super();

        // The button
        JButton button = new JButton("Close");
        button.addActionListener(e -> {
            SwingUtilities.getWindowAncestor((Component)e.getSource()).dispose();
        });

        // The JPanel and nested components
        JPanel startupPanel = new JPanel();
        startupPanel.add(button);
        add(startupPanel);
        pack();

        // Make sure the app exits when closed
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    }

    // Just our entry point
    public static void main(String ... args) {
        SwingUtilities.invokeLater(() -> {
            new SwingStuff().setVisible(true);
        });
    }
}
tresf
  • 7,103
  • 6
  • 40
  • 101