Asked  7 Months ago    Answers:  5   Viewed   27 times

What's the correct way to get a JFrame to close, the same as if the user had hit the X close button, or pressed Alt+F4 (on Windows)?

I have my default close operation set the way I want, via:

setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

It does exactly what I want with the aforementioned controls. This question isn't about that.

What I really want to do is cause the GUI to behave in the same way as a press of X close button would cause it to behave.

Suppose I were to extend WindowAdaptor and then add an instance of my adaptor as a listener via addWindowListener(). I would like to see the same sequence of calls through windowDeactivated(), windowClosing(), and windowClosed() as would occur with the X close button. Not so much tearing up the window as telling it to tear itself up, so to speak.

 Answers

60

If you want the GUI to behave as if you clicked the X close button then you need to dispatch a window closing event to the Window. The ExitAction from Closing An Application allows you to add this functionality to a menu item or any component that uses Actions easily.

frame.dispatchEvent(new WindowEvent(frame, WindowEvent.WINDOW_CLOSING));
Tuesday, June 1, 2021
 
Szenis
answered 7 Months ago
49

Consider using CardLayout instead of hunting for how many JFrames there are. Then..

  • only one JFrame would be needed
  • any of Next/Back Actions will be only switching between cards

There are lots of examples in this forum - e.g. as shown here.

Sunday, August 15, 2021
 
Len_D
answered 4 Months ago
82

There is a simple fix that works almost all the time: make your frame not resizable after having set visible. So only modifies your code this way:

public static void main(String[] args) {

    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();

    JFrame frame = new JFrame("Jedia");
    frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
    frame.setSize(screenSize);
    frame.setVisible(true);    // FIRST visible = true
    frame.setResizable(false); // THEN  resizable = false
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

}

This way, the frame will start maximized and the maximize button will be greyed out, preventing user to use it. (I don't really know why you have to do this. I suppose the maximized state is really applied only when the window becomes visible, and if you make it unresizable before, it will not apply.)

It works almost all the time because on Windows 7 at least you can make the window goes out of the maximized state by clicking the title bar and dragging it. But it will be at the size you have set it earlier. Problem is that your user will not be able to maximize it again, and I haven't found the way with listeners to make the window back to maximized state. ( Edit: @David Kroukamp shows in the last part of his answer that it is possible to force the maximized state by using a ComponentListener. Therefore you don't have to use setResizable(false) This way you still have a problem with Windows 7 because the dragging action is not catched by this event for whatever reason but users will be able to use the maximized button to put it back where it should be.)

Now, there is almost never a reason to do this kind of things. Users don't really like when you prevent them to manipulate their windows (maximized windows can not be moved, for example, and that can be annoying when you have multiple screens). An exception is if you are making a game, which is typically full-screen. But then you wouldn't want a JFrame because you don't want all the decoration, but a Window.

If your problem is that the default window size is very small, it's normal. You have to put something in your frame first (some controls, buttons, what you want in your application), using layouts (that's important) then call the method pack() on your frame. It will chose a nice default size for your window.

Finally, a last word. I've put my example code in a main method as a shortcut, but you should always do Swing stuff in the Swing EDT by using SwingUtils.invokeLater().

Tuesday, August 17, 2021
 
Loui
answered 4 Months ago
72

There are many things wrong with your code.

It starts with wrong comparison of strings ( see here ).

But your actual problem: you are sleeping the event dispatcher thread ( see there )

So your idea of sleeping with an event listener is simply the wrong approach. You can't do it this way. You have to re-think your approach there.

And the real answer here is: you are lacking basic knowledge of Java. Consider learning such basic things first before further overburdening yourself if Swing UI coding.

Your requirement seems to be: after that button was hit - and a certain amount of time passed you want to print something on the console. You can do that like:

public void actionPerformed(ActionEvent event) {
   String command = event.getActionCommand();
   command = event.getActionCommand();
   Runnable printChoice = new Runnable() {
     @Override
     public void run() {
      try{
        Thread.sleep(500);
        if ("choice1".equals(command)){
            System.out.println("choice1");
        }
        else if("choice2".equals(command)){
            System.out.println("choice2");
        }
        else{
            System.out.println("no choice");
        }
      }   
      catch(InterruptedException ex){
        Thread.currentThread().interrupt();
      }
    });
    new Thread(printChoice).start();
}

The above:

  • creates a Runnable that simply waits to then print something
  • uses a new Thread (not the event dispatcher thread) to do that

I didn't run this through the compiler - it is meant as "pseudo code" to give you some ideas how to solve your problem.

But further thinking about this - I think this is going in the wrong direction. You don't want that anything is waiting when you develop a reasonable UI application.

In other words: you think of:

  • button A is clicked - some code starts "looping"
  • when the user makes another choice, that "looping" code notices that and does something

Wrong approach. Instead work along these lines:

  • user clicks a button, and maybe that enables other UI components
  • user does something with those other UI components - triggering other actions

Example: changing radiobuttons causes events to be fired. You should not have a loop that regularly keeps checking those buttons. Instead you define a clear flow of actions/events the user has to follow in order to trigger a certain action.

Tuesday, August 31, 2021
 
geocodezip
answered 3 Months ago
97
  1. use CardLayout

  2. if is there real reason for another popup container

    • use JDialog with parent to JFrame, with setModal / ModalityTypes

    • create only one JDialog and to reuse this one JDialog by getContentPane#removeAll()

    • use JOptionPane for simple users interaction

  3. put both together, above two points, to use CardLayout for popup JDialog with parent to JFrame, notice after switch from one card to another could be / is required to call JDialog.pack()

Thursday, November 4, 2021
 
Classified
answered 4 Weeks ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :  
Share