I think Window.addResizeHandler is a last resort to resize widgets according to the size of the browser window. And I have come to that last resort.
So, I have onResize sizing up my widgets beautifully, except when the application starts up.
How do I trigger at startup of the app, such a widget resize calculation done by onResize?
I cannot/should not tell users to use the mouse to deliberately resize the browser so as to trigger optimal widget distribution.
Sorry for answering my own question. The answer is ...
on module load, use Window.getClientWidth/Height and apply the width/height to the resize routine used by the resize handler.
Add this call after your widget has been initialized or set visible:
Scheduler.get().scheduleDeferred(new ScheduledCommand() {
#Override
public void execute() {
//Resize code here
}
});
}
Note : You don't have to trigger the resize event by using this approach, but just set the size that you want on the widget. You can also go by triggering the event in the execute method if this approach is easier for you. Check this for firing events manually.
Related
I have an application which depending on user input changes the entire content of the JFrame. I do this by removing the JPanel containing the current components and replace it by a new JPanel with new components.
After that one of the components needs to get focus and a JScrollpane should scroll to this component. In most cases this works properly.
Now one scenario leads to a JPanel beeing added, which itself contains more than 500 components. Rendering this takes some time and it seems that scrollRectToVisible() is called at a point, where the UI is not fully rendered. If I debug I can actually see that it first scrolls to the right position, but then further rendering is done and the component is moved out of the viewport again.
So I was trying find a Listener, which is called, when rendering is fully done. I tried with ComponentListener and AnchestorListener. Both didn't receive most of the events I was expecting. But even when they did the callback methods were called before any UI change was visible on the screen.
I swap the JPanels in EDT and call validate() on the JFrame afterwards. After that I do not process any further code. However, if I set a breakpoint in the last executed line and go one step further, the UI has not changed on screen. The EDT is actively doing something (I assume rendering the UI). And I would like to get notified, when the EDT has finished rendering.
Another thing I tried:
If I create another Thread that just sleeps for a few seconds (until the UI is definitely rendered) and call the scrollRectToVisible() then, everything works fine.
I'm sorry not to provide an SSCCE. I tried, but it seems to be rather complex. I really appreciate any idea on how I could get notified on the UI beeing fully rendered and visible to the user.
Thanks
If I create another Thread that just sleeps for a few seconds (until the UI is definitely rendered) and call the scrollRectToVisible() then, everything works fine.
Instead of sleeping, just wrap the scrollRectToVisibl() code in a SwingUtilities.invokeLater(). This will add the code to the end of the EDT so it should be processed after all the other rendering.
Add a property change listener:
jPanel.addPropertyChangeListener(new PropertyChangeListener() {
#Override
public void propertyChange(final PropertyChangeEvent evt) {
System.out.println(evt);
}
});
Produces something like:
java.beans.PropertyChangeEvent[propertyName=ancestor; oldValue=null; newValue=javax.swing.JPanel[null.contentPane,0,0,0x0,invalid,layout=javax.swing.JRootPane$1,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]; propagationId=null; source=javax.swing.JPanel[,0,0,0x0,invalid,layout=java.awt.FlowLayout,alignmentX=0.0,alignmentY=0.0,border=,flags=9,maximumSize=,minimumSize=,preferredSize=]]
Maybe JComponent.addNotify() is what you need.
If you override that method, make sure that you call the super.addNotifty() as well!
I am going through a legacy application which is using Swing and i am struggling to figure out how the screens are changing when a user clicks a button. One of the reasons i cant figure this out is because this is the first time i am using Swing. I have read a book and got the basics but still struggling.
Basically, the screen i am looking at has a JSplitPane which has a number of shortcut buttons on the left and an empty pane on the right. When i click on the button, the right side pane is populated with a different screen depending on the button pressed.
Going through the code, i was expecting somewhere that there will be something that calls a setVisible() method depending on which button is pressed.
The actionPerformed method for each of the shortcut buttons looks something like this:
void shortCutBtn_actionPerformed(ActionEvent e) {
propertyChangeListeners.firePropertyChange("selectedShortCut", previousShortCutSel, currentShortCutSel);
mainPanel.updateUI();
}
I have gone through most of the code and came to a conclusion that the above code is what is causing the frame switching but i dont understand how that is happening.
Each screen is identified by a numeric constant. In the above code example, previousShortCutSel and previousShortCutSel refer to a numeric value that represents individual screens screen.
I have tried to look for documentation of how updateUI() works but i am lost. How does the above cause the content of the right panel of the JSplitPanel to be updated with a new screen?
This is not an appropriate use of updateUI(), which "Resets the UI property to a value from the current look and feel." As the example itself may be unreliable, consider studying another. GoogleOlympiad, for example, sets a label's icon using a (cached) image.
ImageIcon image = getImage(index);
imageLabel.setIcon(image);
(source: drjohnbmatthews at sites.google.com)
As per comments by ziggy (glad it helped)
Have a look at the PropertyChangeListeners that appear to be added in the code. In particular the propertyChange(PropertyChangeEvent e) method is where the code which changes the content will be present.
+1 to trashgod nice example/advice as always
I have a simple program that utilizes Java Swing Timer to display an image for 400 miliseconds, in this period of time I just want to stop all ActionListeners or stop taking ActionEvents. I've got 40+ buttons and want a simple way to do this.
Is there anyway to do that in Java?
Can you determine that you are in this "image displayed" state? The image goes up and you set the state to "image displayed" or whatever. Go through your widgets and decide which ones are supposed to be dead while the image is up. Turn them into Observers of this state value. When the state changes, they either enable or disable, as appropriate. The image code doesn't do anything directly to any widget. It just declares that the state is now "image displayed". It's up to the Observers to decide what to do, if anything, with that information.
Or use the GlassPane. That works too. Of course, the GlassPane shuts down everything. If you need to be more selective, you need a more fine-tuned approach.
You can use a temporary GlassPane instance to consume all events by registering empty listeners to it.
Use an undecorated modal JDialog to display the image. Before you make the dialog visible you would start a Timer. When the Timer fires in 400 ms you close the dialog.
I've had similar issues and typically found that its a design issue that got me in that situation. Being the case, I still had to find away around it. To fix the issue, I kept a list of the elements that I wanted to disable (stop listening) and iterated through them at the beginning and end of the timer. For buttons it should be as simple as:
for(Component c : listOfToggledComponents){
c.setEnabled(shouldItBeEnabled);
}
For buttons, this will grey out the button. Similar things happen to other swing components.
I have a Java app that launches, creates a GUI and works great. If the user changes the screen resolution (switches from 1440x900 to 1280x768), I'd like to be able to listen for that event.
Any ideas?
PS - I'd like to do this in event/listener mode, not in poll mode, so that extra CPU cycles aren't wasted on something like a timer constantly polling the screen size every N seconds to see if it's changed.
This post is old, but:
- polling the screen size once every second will not have any impact on performance
- when the screen is resized, every window should receive a repaint() call (you need to test this for the OSs you target)
I don't think that Java can do this by itself. You would have to have a "hook" into the operating system that detects this change and may wish to consider using JNA, JNI, or a separate utility such as perhaps Sigar that reports to your Java program. Out of curiosity, why do you wish to do this? Is it for a game you're making or so that you can re-size a GUI application?
Apart from Hovercrafts's suggestion you might consider a background thread that checks the current screen resolution using Toolkit.getScreenSize().
You would need to test this to find out how big the performance impact of that thread to the system is. How often it checks for changes depends on your requirements (how quick your application needs to react to the change)
You can create a global PAINT listener to detect screen resize.
// screen resize listener
Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
#Override
public void eventDispatched(AWTEvent event) {
// take a look at http://stackoverflow.com/questions/10123735/get-effective-screen-size-from-java
Rectangle newSize = getEffectiveScreenSize();
if (newSize.width != windowSize.width || newSize.height != windowSize.height)
resize();
}
}, AWTEvent.PAINT_EVENT_MASK);
Here is my suggestion for this problem,
Every swing object can implement an interface called java.awt.event.ComponentListener.
One of its method is componentResized(ComponentEvent e).
Your main application frame should implement this interface and override the resize event method.
This is how you listen to the resize event, Checkout this link . I hope this helps you.
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.