smoes
smoes

Reputation: 601

Java Swing redraw delay

I'm writing a little private application at the moment which utilizes the Wolfram Alpha Java Bindings. The application's GUI is realized using Swing. My Wolfram Alpha Plugin has a function looking like this:

public void fire(String value) {

    // This sets the field state to loading
    _state = loading;

    // This tells the controller to redraw the window
    // When reading the state of the plugin it sets an
    // animated gif at a JPanel. This should be displayed
    // before the application is blocked by the Wolfram Alpha
    // Request. 

    // updateInput does nothing more then call repaint after some
    // other function calls. No special threading included. 

    getController().updateInput("");


    // My wolfram request follows:

    WAQuery query = _engine.createQuery();
    query.setInput(value);
    try {
        // For educational purposes, print out the URL we are about to send:
        System.out.println("Query URL:");
        System.out.println(_engine.toURL(query));
        System.out.println("");

        // This sends the URL to the Wolfram|Alpha server, gets the XML result
        // and parses it into an object hierarchy held by the WAQueryResult object.
        WAQueryResult queryResult = _engine.performQuery(query);

        if (queryResult.isError()) {
            System.out.println("Query error");
            System.out.println("  error code: " + queryResult.getErrorCode());
            System.out.println("  error message: " + queryResult.getErrorMessage());
        } else if (!queryResult.isSuccess()) {
            System.out.println("Query was not understood; no results available.");
        } else {
            // Got a result.
            System.out.println("Successful query. Pods follow:\n");
            for (WAPod pod : queryResult.getPods()) {
                if (!pod.isError()) {
                    System.out.println(pod.getTitle());
                    System.out.println("------------");
                    for (WASubpod subpod : pod.getSubpods()) {
                        for (Object element : subpod.getContents()) {
                            if (element instanceof WAPlainText) {
                                System.out.println(((WAPlainText) element).getText());
                                System.out.println("");
                            }
                        }
                    }
                    System.out.println("");
                }
            }
            // We ignored many other types of Wolfram|Alpha output, such as warnings, assumptions, etc.
            // These can be obtained by methods of WAQueryResult or objects deeper in the hierarchy.
        }
    } catch (WAException e) {
        e.printStackTrace();
    }


}

The Problem is that the request is started BEFORE the window is repainted. I have a request delay of about one second and THEN the loading animation is displayed. This animation should be displayed before the request is started.

What I tried so far:

What am I overseeing here?

Upvotes: 0

Views: 212

Answers (2)

Hovercraft Full Of Eels
Hovercraft Full Of Eels

Reputation: 285405

What I suggest is:

  • Use background threading, specifically a SwingWorker'
  • Do the long running code in a SwingWorker's doInBackground method.
  • Start your animation display before executing your SwingWorker.
  • Give the SwingWorker a PropertyChangeListener, and when the SwingWorker's state is done, then stop the animation.
  • Be sure that the animation does not tie up the Swing event thread either. Use a Swing Timer for it.

For example,

  // start animation -- be sure to use a Swing Timer or
  // other way to prevent tying up the Swing event thread

  SwingWorker<Void, Void> myWorker = new SwingWorker<Void, Void>() {
     protected Void doInBackground() throws Exception {
        fire(someValue);
        return null;
     };
  };
  myWorker.addPropertyChangeListener(new PropertyChangeListener() {

     @Override
     public void propertyChange(PropertyChangeEvent pcEvt) {
        if (pcEvt.getNewValue().equals(SwingWorker.StateValue.DONE)) {
           // .... stop the animation here
        }
     }
  });

  myWorker.execute();

Upvotes: 2

Braj
Braj

Reputation: 46841

I have a request delay of about one second and THEN the loading animation is displayed. This animation should be displayed before the request is started.

Never use Thread.sleep() in Swing application that sometime hangs the whole application as you stated it already in your post. You should use Swing Timer in that case.

Please have a look at How to Use Swing Timers

Sample code:

Timer timer = new Timer(1000, new ActionListener() {

    @Override
    public void actionPerformed(ActionEvent arg0) {            
        // start loading animation now
    }
});
timer.setRepeats(false);
timer.start()

Upvotes: 2

Related Questions