Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 594
Luhar Avatar asked Feb 26 '10 10:02

Luhar


1 Answers

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.

like image 182
Reverend Gonzo Avatar answered Sep 28 '22 08:09

Reverend Gonzo