Why is my Swing application minimizing when I create a dialog? - java

I have a simple Swing application which runs in full screen mode. My application instantiates a JFrame, which in turn instantiates a JPanel, where all of the drawing is done in the paintComponent method. I also have a MouseListener watching for certain events.
One of those events (clicking on a certain area of the screen) triggers a prompt. Here is my code to show the prompt (keep in mind this comes from within my class that is extending JPanel).
int choice = JOptionPane.showConfirmDialog(this, "Are you sure you want to quit?", "Quit?", JOptionPane.YES_NO_OPTION);
if ( choice == JOptionPane.OK_OPTION ) {
dialogOpen = false;
System.exit(0);
} else {
dialogOpen = false;
repaint();
}
The only trouble is... as soon as this code runs, the entire window disappears. More specifically, it looks like it minimizes itself, because I can click on the Java icon in the taskbar and it pops right back up. But how do I stop it from minimizing itself? All I want to do is display a simple prompt!

I figured it out. Thanks to everyone for their helpful comments (what is it with people and commenting here, by the way? how come people write everything that could go in an answer in the comments instead?)
Rather than calling .showConfirmDialog(this, ...) (where this is my JPanel subclass), I needed to call .showConfirmDialog(parent, ...) (where parent is my JFrame subclass). Then, I added a WindowStateListener on the JFrame to detect state changes and reset the window state.

Related

Java: Close Specific JFrame Window

I hope everyone is doing well.
I've built a hangman game with a swing gui and everything works well enough, HOWEVER I am trying to make a popup show up by constructing a new JFrame object when the user wins or loses with a "you lose" message or what have you. No problem, but I want a specific window to close when activating the button listener on the popup, or when the 'x' is clicked. Assume my program has 3 windows up, and I only want to close 2 of them with one click.
I tried stuff in the area of
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
But that specific one closes all the windows. If you want to see more specific sample code, I would happy to provide it, but it didn't seem necessary for this question.
Either way, I can't figure out how to do this. Is this possible using Swing?
Thank you so much in advance. You guys are always so helpful.

How can you keep a JPanel from closing on System.exit(0)

I have a program that I am terminating with the System.exit(0); command.
When this happens the JPanel closes. I would like it to rename open so I can view the state at termination. Is there a way of keeping the Jpanel open or is there a better command than System.exit()?
not sure why a down vote I asked a simple question and someone answered it. I can't do it that way so try something else. Going to use a true false to test where to enter the simulation loop.
regarding:
Is there a way of keeping the Jpanel open or is there a better command than System.exit()?
The best solution: Don't call System.exit(...). Why? Because System.exit(0) closes the JVM, and so all Java processes running on that JVM will shut down when System.exit(0) is called.
As for "better command", that all depends on your need. If you just want to close a window such as a JDialog, then call myWindow.setVisible(false);. If you want to close it and release resources, then myWindow.dispose();.
Note: I suspect that you might have multiple windows open, perhaps multiple JFrames. If so, I strongly urge you to read: The Use of Multiple JFrames, Good/Bad Practice?
You also posted in comments:
I would like to keep the Jpanel open, but stop the simulation from running. I need to stop the Sim when certain conditions are met. so I wrote a stop()
So your question is in fact an XY Problem where you ask how to solve a specific code problem (keep a JPanel open after calling System.exit(0)) when the best solution is to use a completely different approach. Better that you tell us the overall problem that you're trying to solve rather than how you're currently trying to solve it, because System.exit isn't going to be part of the best solution.
Likely the best solution is to well separate your simulation model from its view (the GUI), to be able to give the model functionality that allows it to stop without closing down the JVM -- impossible for me to say how given our current level of knowledge about your problem -- and then reflect the stopping of the model in the view, again without shutting down the system.
The key to all of this will lie in the details of your current program, including the logic that underpins your simulation, and if you need more specific and likely more helpful answers, you're again going to want to improve your question, providing us with much more specific information about your code, your problem and with posting of pertinent code, preferably as a minimal example program.
Have you tried an approach similar to:
Do something when the close button is clicked on a JFrame
Basically, you're grabbing the Window closing event by setting a listener on the frame
You can then .dispose() the appropriate jpanel/frame if you want
JFrame is window and JPanel is a container. The moment the JPanel instance loses its reference, it will be garbage collected
How can JPanel be disposed after the panel has been removed from the JFrame
Disposing JFrame by clicking from an inner JPanel
import javax.swing.JOptionPane;
/*Some piece of code*/
frame.addWindowListener(new java.awt.event.WindowAdapter() {
#Override
public void windowClosing(java.awt.event.WindowEvent windowEvent) {
//delete this code if you want and replace with .dispose() or anything
if (JOptionPane.showConfirmDialog(frame,
"Are you sure to close this window?", "Really Closing?",
JOptionPane.YES_NO_OPTION,
JOptionPane.QUESTION_MESSAGE) == JOptionPane.YES_OPTION){
//choose to close JVM here if you want
System.exit(0);
}
}
});
Here's a way, by overriding the SecurityManager for the JVM:
//set your security manager
static{
SecurityManager s = new DontCloseOnExitSecurityManager();
System.setSecurityManager(s);
}
static class DontCloseOnExitSecurityManager extends SecurityManager{
public void checkExit(int code){
//here you can put a check to see if you really do want to close - like if the JFrame is still open.
if(/*do some check*/ 13 == code)
super.checkExit(code);
throw new SecurityException("13 is unlucky, you shouldn't system exit on it.");
}
}
}
You'll need to find an appropriate place to put it in, and also how to do your checks (in checkExit).
Apologies for inaccuracies, I'm not in front of an IDE to test this right now.

Presenting a JFrame synchronously

I have this main JFrame (call it DrinkChooser) that shows another complex confirmation JFrame (call it ConfirmWin).
The ConfirmWin has only two JButtons, confirm and cancel.
I want to do this:
(in DrinkChooser, assume drinksChoosen is a Drink[])
public void handleAction(){
int choice = ConfirmWin.showDrinkConfirmation(drinksChoosen);
if(choice == ConfirmWin.CONFIRM)
//Handle confirmation.
else
//handle cancel, do nothing.
}
I want to achieve an effect that is as close as possible to the "JOptionPane effect", which is that the original DrinkChooser gets suspended, and the ConfirmWin returns the choice of the user.
Thanks.
Have a look at the trail How to Make Dialogs.
A Dialog window is an independent subwindow meant to carry temporary notice apart from the main Swing Application Window. Most Dialogs present an error message or warning to a user, but Dialogs can present images, directory trees, or just about anything compatible with the main Swing Application that manages them.
For convenience, several Swing component classes can directly instantiate and display dialogs. To create simple, standard dialogs, you use the JOptionPane class.
Here is a possibly related question:
Java - How to create a custom dialog box?
Don't forget that the value argument of all JOptionPane.showXXXX methods can be a JComponent. If you pass a component (in your example it might be a JList with a custom renderer), it will be embedded within the dialog and can be used to customize the appearance.

Is it possible to bring JFrame to front but NOT focus?

I'm writing a Java app (Swing GUI) that periodically pops up a JFrame.
Is it possible somehow to bring the window to front (foo.setAlwaysOnTop(true) would be even better) but without having it focus?
Some people move their eyes away from the screen from time to time to look at their keyboard while typing, and I'm sure that if this window would always capture the keyboard focus people would get really annoyed as it's causing them to lose quite a few keystrokes every time it pops up unnoticed.
In other cases, even when the user is actually capable of typing without looking at the keyboard all the time, having a window pop up and get focus could cause unwanted actions from the pop-up window itself (some Tab+Enter combination for example, where the user accidentally selects an option she really wouldn't had selected otherwise).
Thanks in advance!
Update
As Jonas suggests, foo.setFocusableWindowState(false); seems to work if called after the window has been rendered (tested on Gnome only).
This does not work:
foo.setFocusableWindowState(false);
foo.setVisible(true);
foo.setFocusableWindowState(true);
However, this does:
foo.setFocusableWindowState(false);
foo.setVisible(true);
Thread.sleep(1000);
foo.setFocusableWindowState(true);
I'll have to see if there's an event I can catch/listen to that allows me to do foo.setFocusableWindowStatue(true); when appropriate.
I consider my problem solved.
This may work:
foo.setFocusableWindowState(false);
As of Java 1.7 you can call
frame.setAutoRequestFocus(false);
I recently ran into the same problem, and the tentative solution has been:
JFrame frame = ...;
frame.setExtendedState(JFrame.NORMAL);
frame.setAlwaysOnTop(true);
frame.requestFocus();
frame.setAlwaysOnTop(false);
Suggestion: In the GUI Component that creates the Frame, put 2 consecutive calls:
frameJustCreated.requestFocus();
this.requestFocus();
1st one bring the window of the new JFrame to the top, 2nd one keeps the window where the user is typing at the top.
If you want to call setFocusableWindowState(true) in an event (so, not to wait e.g. 1 second), you can add a WindowListener (e.g. derived from WindowAdapter) that changes the property:
appFrame.addWindowListener(new WindowAdapter() {
#Override
public void windowOpened(WindowEvent e) {
super.windowOpened(e);
e.getWindow().setFocusableWindowState(true);
}
});
appFrame.setFocusableWindowState(false);
appFrame.setVisible(true);
JInternalFrame toFront() calls to moveToFront()
Override moveToFront()
public void moveToFront() {
Window window = SwingUtilities.getWindowAncestor(this);
Component focusOwner = (window != null) ? window.getFocusOwner() :
null;
boolean descendant = false;
if (window != null && focusOwner != null &&
SwingUtilities.isDescendingFrom(focusOwner, this)) {
descendant = true;
requestFocus();
}
super.moveToFront();
if (descendant) {
focusOwner.requestFocus();
}
}
the fix is in moveToFront to check if a child has focus, if it does, then temporarily request focus on the internal frame. After the internal frame has movthe ed to front, then request focus back on the previously focused component. This will ensure the appropriate events are generated.
refer
https://bugs.openjdk.java.net/browse/JDK-4309079

Java Swing: Do something when a component has *finished* resizing

Apologies for the somewhat unclear question - couldn't think of a better way of putting it.
I use a JXTaskPane (from the Swing labs extension API) to display some information.
The user can "click" the title to expand the panel. The JXTaskPane is in a container JPanel, which is then added to a JFrame, my main application window.
I want my application window to resize to the size of the expanded task pane. To achieve this, I added a component listener to my container JPanel which would set size to the now expanded panel.
panel.addComponentListener(new ComponentListener()
{
public void componentResized(ComponentEvent e)
{
Dimension newSize = ((JXTaskPane)e.getSource()).getSize();
reSizeFrame(newSize);
}
}
private void reSizeFrame(Dimension newSize)
{
if ((newSize.height < maxSize.height) && (newSize.width < maxSize.width))
{
containerPanel.setSize(newSize);
appFrame.setSize(containerPanel.getSize());
appFrame.pack();
}
}
The problem is that the componentResized method is called as the task pane expands, as a result the resizeFrame method is called lots of times, and looks really awful on the screen.
How can I detect when the JXTaskpane has finished resizing? I thought of two approaches:
Put the resizeFrame() method in a SwingUtilities.invokeLate(..) call.
Put in a timer resizeFrame call, so any subsequent calls do not do anything until the timer fires. This should give enough time for the panel to resize.
What is the best way forward?
Also - This is my first serious Java GUI app after years of server side program. StackOverflow has been very helpful. So thanks!
I know you've already selected an answer, but overriding the paint method is definitely not correct, and while you may be able to hack something in place, it won't be ideal.
Looking at the source for JXTaskPane and specifically looking in setExpanded() (line 387), you can see it calls JXCollapsiblePane.setCollapsed(...) and then fires a property change event for expanded. A listener on that property won't be correct, because it'll fire before the animation is complete. So, if you go into JXCollapsiblePane and look at setCollapsed(...) (line 470) you'll see that if it's animated, it sets the paramaters and starts a timer. We want to know when the animation ends, so in that file, look at the animator (line 620, and specifically 652-667), which shows that when the animation ends, it fires a property change for ANIMATION_STATE_KEY with a value of "collapsed" or "expanded". This is the event you actually want. However, you don't have access to JXCollapsiblePane, so go back to JXTaskPane and search for ANIMATION_STATE_KEY, and you find line 208, which shows that JXTaskPane creates a listener on JXCollapsiblePane.ANIMATION_STATE_KEY and refires it as it's own event.
Since you do have access to JXTaskPane, you can listen for that event, so doing ...
taskPane.addPropertyChangeListener(JXCollapsiblePane.ANIMATION_STATE_KEY, new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
if(e.getNewValue().equals("expanded") {
...
}
else if(e.getNewValue().equals("collapsed") {
...
}
}
}
should get your event exactly when you want it.
The correct way to listen for events in Swing is through property listeners. Unfortunately, the only way to find out what the correct properties and values are is by digging through source code.
As a suggestion, have you tried overriding the paint method, first calling super and then putting your resize code at the end of that if (and only if) the size has changed significantly.
I'm not familiar with JXTaskPane, but my first reaction is that maybe you're handling the wrong event. You want the frame to resize when the user clicks on the header - so why not handle that event (perhaps using EventQueue.invokeLater() to resize the frame after the task pane has been resized)?
But if that doesn't work and you need to use the approach you've outlined above, using a javax.swing.Timer is probably best. Set it for 200 milliseconds or so and just restart() it every time componentResized() fires.

Categories