views:

191

answers:

3

In my application I fetch data if component is resized. I want to delay the fetch till user completes resize operation. ComponentListner event componentResized fires every time the window is resized.

A: 

This is not possible. But you can use SingleWorkerThread to minimalize the number of events processed.

Rastislav Komara
+1  A: 

This isn't possible via conventional means, I'm afraid. componentResized() will be called for every intermediate sizing change, and there is no way to determine if the current call will be the last.

Strictly speaking, what you are attempting isn't a conventional thing to do. Data loads can be expensive IO operations and are usually best performed when the user is expecting them after a more direct UI operation such as a button press, when appropriate feedback can be displayed as a result of their action. The size of a component can change for innocent reasons such as the frame being maximised or arranged as a result of an operation elsewhere, such as the new Aero operations in Windows 7.

Some applications do perform IO as a result of sizing. Google Reader, for instance, can load older posts from RSS feeds as a result of moving the scrollbar on the browser window. This is a nice feature, and does away with the need for an explicit load button, but it is directly driven by the user seeking the older posts; a conscious action, not an unconscious one.

I guess my point is that you need to be very careful about how you make this work. Punishing a user with a slow IO operation that makes them wait simply because they dared resize the window is not a user-friendly approach!

You give precious little information in your question about what your UI looks like, or what the component is or how it gets resized - even, where you are loading data from, so it's kind of difficult to answer. Here are a couple of suggestions: I hope they help.

1. Load the data into memory beforehand, and just display it
If the data model isn't too big you could just load it into memory, and redraw it quickly with every resize event. The Event-Dispatch-Thread will combine resize events together so your listener is not overwhelmed by requests. This might be a non-starter for you, but it's worth mentioning.

2. Be eager to load
Load more data than you need on the first resize event, and then either reject or cache the data you don't use. If you're populating the rows of a table or a list this might be the better approach; tabular data is usually straight-forward to load and parse.

3. Allow a reasonable time to pass for resizing to stop
The first resize event starts a Timer with a 1 second countdown. Any subsequent resize events reset the 1 second countdown. At some point there will be a final resize event after which no subsequent resize events reset the countdown so it is allowed to expire. At this point the Timer does your load for you.

Three is the safest, most accurate approach, in my opinion. You can make your application feel responsive by visibly indicating that data is loading on the first resize event, and adjust the countdown of the timer to get the feel of your application right.

banjollity
A: 

I'd say you are propably writing a mapping application of some kind? :-)

You can use the swing Timer class to wait until a specified amount of time passed without any events. Here's the code :

/** Time to wait */
private final int DELAY = 1000;
/** Waiting timer */
private javax.swing.Timer waitingTimer;

/**
 * Handle resize event.
 */
public void componentResized(ComponentEvent e) 
{
  if (this.waitingTimer==null)
  {
    /* Start waiting for DELAY to elapse. */
    this.waitingTimer = new Timer(DELAY,this);
    this.waitingTimer.start();
  }
  else
  {
    /* Event came too soon, swallow it by resetting the timer.. */
    this.waitingTimer.restart();
  }
}

/** 
 * Actual resize method
 */
public void applyResize()
{
  //...
}

/**
 * Handle waitingTimer event 
 */
public void actionPerformed(ActionEvent ae)
{
  /* Timer finished? */
  if (ae.getSource()==this.waitingTimer)
  {
    /* Stop timer */
    this.waitingTimer.stop();
    this.waitingTimer = null;
    /* Resize */
    this.applyResize();
  }
}
xastor
Thanks for spending your time to write detailed example; this solution seems to fit my requirement.
Krishna Kumar