JFrame (extended) state, iconified/maximized/normal question

There have been a few posts on this in the past but I was unable to find a complete solution

This is a doosy!

I am trying to preserve(store) the frame window NORMAL size and position so that it can be re-instated the next time the application is run.

I am using ComponentListeners to monitor move and resize events and capture and save the window bounds with getBounds() in those events.

When my app exits I save the last captured window bounds, next time it runs I load the window bounds and call setBounds(..) to restore the last window position.

I also save and restore the getExtendedState() to restore the NORMAL, or MAXIMIZED window

One exception is that I do not want to capture and store the window bounds when the window is MAXIMIZED! This would result in my application re-instating the maximum window position and dimensions next time it runs when what I want is the NORMAL position and dimensions.

So in the event listeners I check to see if the getExtendedState() is MAXIMIZED_BOTH and if so I do not store the bounds. (I have also tried the reverse of this, only storing bounds when getExtendedState() is NORMAL)

That's the intuitive way to do it, that's the way all the previous posts indicated to go, but it does not work!

The problem is that the events are queued and by the time they are dispatched by AWT and I query the window with getBounds() I get unpredictable results...

sometimes I get NORMAL window bounds , a Rectangle(100,50,650,400)

sometimes I get partially MAXIMIZED window bounds, Rectangle(-4,-4,650,400)

and sometimes I get fully MAXIMIZED window bounds Rectangle(-4,-4,1024,768)

The reason (I think) is that depending on how much time elapses between the event being queued, dispatched and my listener eventually being called .... the actual frame window may be in a NORMAL position 10,50,640,400 if the timing was fast, may be partly maximized where it has been moved to position -4,-4 but still retains its NORMAL size of 650,400 if the timing was medium or may be fully maximized in position -4,-4 with max width and height of 1024,768 if the timing was slow!

I need a way to get an event that contains both the window state NORMAL/MIN/MAX and that contains window bounds all in one event without having to query the frame for these values?

Or

I need to be able to ignore the events that have partially MAXIMIZED data. I have attempted this but getExtendedState() does not always return MAXIMIZED, sometimes it returns NORMAL even though partial window movement has occurred and is why I end up storing partial data.

this code outputs the getBounds() and window state data in various events and is followed by the output

...

addWindowStateListener(new WindowAdapter(){

publicvoid windowStateChanged(WindowEvent e){

if (e.getNewState()==Frame.MAXIMIZED_BOTH){

// For information purposes only

System.out.println("IN windowStateChanged state=" + extendedStateToString(e.getNewState()));

}

}

});

// Add listener for frame resize events to persist the users curent window size preferences

addComponentListener(new ComponentAdapter(){

publicvoid componentMoved(ComponentEvent e){

// This is where I would store the window bounds if the window was in NORMAL state

System.out.println("IN componentMoved getBounds()= " + getBounds() +", getExtendedState()=" + extendedStateToString(getExtendedState()));

}

publicvoid componentResized(ComponentEvent e){

// This is where I would store the window bounds if the window was in NORMAL state

System.out.println("IN componentResized getBounds()= " + getBounds() +", getExtendedState()=" + extendedStateToString(getExtendedState()));

}

});

...

public String extendedStateToString(int state){

switch (state){

case Frame.MAXIMIZED_BOTH:

return"MAXIMIZED_BOTH";

case Frame.MAXIMIZED_HORIZ:

return"MAXIMIZED_HORIZ";

case Frame.MAXIMIZED_VERT:

return"MAXIMIZED_VERT";

case Frame.NORMAL:

return"NORMAL";

}

return"unknown";

}

Sample output

Notice the first component moved event reports normal window bounds and state = NORMAL, The results of me moving the window. Prefect! I would store this value as the new window position and size

IN componentMoved getBounds()= java.awt.Rectangle[x=953,y=8,width=724,height=425], getExtendedState()=NORMAL

Then notice the component moved event a reports a partially maximized window bounds -4,-4 nut same size as above and worse of all window state still NORMAL! ARggh... I don't want to store this but the window state still reports NORMAL and the data would be saved

IN componentMoved getBounds()= java.awt.Rectangle[x=-4,y=-4,width=724,height=425], getExtendedState()=NORMAL

Now we get a state changed event

IN windowStateChanged state=MAXIMIZED_BOTH

Followed by a resized event reporting maximized window bounds and MAXIMIZED state, this is OK cause I would filter out this event as has a state of MAXIMIZED!

IN componentResized getBounds()= java.awt.Rectangle[x=-4,y=-4,width=1688,height=1058], getExtendedState()=MAXIMIZED_BOTH

[6821 byte] By [JuniperTraila] at [2007-11-27 6:46:16]
# 1

I think JInternalFrame has a notion of the "normal" bounds you can get. But JFrame does not. I subclassed JFrame to do that by adding these methdods...

/**

* Gets the normal bounds. This is the bounds used when restoring from

* maximized or iconified states.

* @return the normal bounds

*/

public Rectangle getNormalBounds()

{

if (this.normalBounds != null)

{

return this.normalBounds;

}

else

{

return getBounds();

}

}

/* (non-Javadoc)

* @see java.awt.Frame#setExtendedState(int)

*/

public synchronized void setExtendedState(int state)

{

boolean isMaximized = ((state & MAXIMIZED_BOTH) != 0);

Rectangle bounds = getNormalBounds(); // current normal bounds

super.setExtendedState(state);

// if maximized in any direction, set normal bounds to whatever the

// pre-maximized bounds were

isMaximized = ((getExtendedState() & MAXIMIZED_BOTH) != 0);

if(isMaximized)

{

setNormalBounds(bounds);

}

else // not maximized, null normal bounds

{

setNormalBounds(null);

}

// if the normal bounds is not the same as the current bounds,

// make the bounds the "normal" bounds.

if(!isMaximized && !bounds.equals(getBounds()))

{

setBounds(bounds);

}

}

/**

* Sets the normal bounds.

* @param r the bounds

*/

public void setNormalBounds(Rectangle r)

{

this.normalBounds = r;

}

bsampieria at 2007-7-12 18:18:44 > top of Java-index,Desktop,Core GUI APIs...
# 2

Hi,

I'm having this same problem at the moment, and so I tried the above solution. Looks like it should work, but I can't get it to. The setExtendedState() override in my subclass of JFrame isn't being called when I maximize or minimize the window. I copy and pasted directly from your example, and added the @Override annotation, so I don't believe I am spelling it wrong, or something equally stupid. Any ideas?

Edit:

Also, I'm running XP and using JDK 1.6.0_01.

- Hollis

Message was edited by:

hwaite

hwaitea at 2007-7-12 18:18:44 > top of Java-index,Desktop,Core GUI APIs...
# 3

Hm... Well when I did it, I was using a custom L&F in which we had not window decorations and the titlebar was calling setExtendedState directly. So perhaps if the OS controls the window decorations, it doesn't call setExtendedState. Maybe if you can try with a L&F decorated window?

If that's the case, then I'm not sure what you can do, because by the time the window events fire, it's probably too late.

bsampieria at 2007-7-12 18:18:44 > top of Java-index,Desktop,Core GUI APIs...
# 4
Ah. OK. That's probably it. I'm not sure if I'm ready to do the L&F thing. Maybe I'll just live with the slightly buggy behavior, but it really seems like there ought to be a way to do this...- Hollis
hwaitea at 2007-7-12 18:18:44 > top of Java-index,Desktop,Core GUI APIs...