javajtabledelaylistselectionlistener

Delay in ListSelectionListener event


I have an ordinary JTable and a ListSelectionListener. It works as it should, I guess, but there is one problem:

  1. I click on a table row
  2. The event fires (method valueChanged kicks in)
  3. Inside valueChanged I start an http request (takes a couple of ms)
  4. The table row gets visibly selected (blue background)

This produces a noticable delay.

Can I change the order of the events? I'd like to have the blue background first, then doing the http request. Inserting a sleep timer in the valueChanged method makes the selection wait until the timer is finished.


Solution

  • You should probably do the HTTP request on a background thread. This will also have the advantage of keeping the UI responsive if it takes an abnormally long time.

    You'd end up with code something like this, depending on what your needs actually are:

    private static class HttpWorker extends SwingWorker<Void, Void> {
        private final String url;
        private HttpWorker(String url) {
            this.url = Objects.requireNonNull(url);
        }
        @Override
        protected Void doInBackground() {
            // do request, possibly producing some result
        }
        @Override
        protected void done() {
            if (!isCancelled()) {
                // update UI
            }
        }
    }
    
    private HttpWorker worker;
    
    @Override
    public void valueChanged(ListSelectionEvent e) {
        if (worker != null) {
            // preserve apparent order of operations if
            // the user selects something different while
            // a background task is already running
            worker.cancel(true);
            worker = null;
        }
        worker = new HttpWorker(...);
        worker.execute();
    }
    

    doInBackground can generally take any action as long as you don't interact with the Swing UI from it.

    Also see the SwingWorker tutorials and documentation.


    For the sake of a complete answer, doing the following at the start of the list selection event may work:

    jlist.paintImmediately(0, 0, jlist.getWidth(), jlist.getHeight());
    

    That's at least insofar as paintImmediately is specified to do what's implied:

    Paints the specified region in this component and all of its descendants that overlap the region, immediately. [...] This method is useful if one needs to update the display while the current event is being dispatched.

    The reason I wouldn't recommend using that is that there's no particular reason that the JList needs to be updated before our own listener such that the list would actually paint the new selection.

    There's also the issue that heavy-duty tasks like HTTP requests generally shouldn't be done on the Swing thread, because it freezes the UI. Even in cases where you want the user to wait for awhile, you wouldn't do the task directly on the Swing thread. You'd do it in a background thread and pop up a modal dialog box, possibly giving the user the option to cancel the task prematurely.