1

I am using a scheduledexecutorservice to perform an animation for drawing a graph(one vertex and one edge at a time). I have a problem in updating the actual UI step by step and instead I can't see the actual animation but only the final graph.

private Runnable newRunnable() {
    return new Runnable() {

        @Override
        public void run() {
            // this method just adds the graph to a JPanel
            displayDiagram();
        }
    };
}

private void animate() {
    executorService.schedule(newRunnable(), 1500, TimeUnit.MILLISECONDS);
    executorService.shutdown();
    try {
        executorService.awaitTermination(1, TimeUnit.SECONDS);
    } catch (InterruptedException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    executorService = new ScheduledThreadPoolExecutor(1);
}

What I want to achieve is to be able to draw one vertex and one edge, and update the UI every time and then wait for 1500ms and do that again until the whole graph is displayed.

Method animate would be called multiple times as the graph is dynamically being created.

roniko1994
  • 51
  • 8
  • This "_executorService.awaitTermination_" does exactly what it says on the tin - it **waits**. Don't call this. Use a `SwingWorker`. – Boris the Spider Jan 24 '16 at 22:45

2 Answers2

3

awaitTermination is a blocking method. Instead you should either be using a SwingWorker (and taking advantage of it's publish/process functionality) or a Swing Timer.

Take a look at Concurrency in Swing, Worker Threads and SwingWorker and How to use Swing Timers for more details

Maybe something like this

Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • 2
    Concurrency in action -- concurrent answers to a question. – Hovercraft Full Of Eels Jan 24 '16 at 22:47
  • Parallel thinking :P – MadProgrammer Jan 24 '16 at 22:47
  • I tried using a Timer but I didn't succeed. I don't know how to wait for the timer to complete before processing the rest of the code. – roniko1994 Jan 24 '16 at 22:51
  • @roniko1994 looks like you need to use a `SwingWorker`. It will fire up an event when it's cooked. Swing is **event driven**. You shouldn't _wait_ for things to happen. Much like real life - I presume you didn't stare blankly at the screen until @MadProgrammer kindly answered your question; you waited for SO to notify you something had happened... – Boris the Spider Jan 24 '16 at 22:52
  • @roniko1994 It all comes down to needs and expectations. In order to animate something, you generally know where the object will end (in your case you do). So, in your `Timer`, when the object reaches it's target point, you can then stop the current `Timer` and make a call to another method. Depending on how re-usable you want the solution, you could even generate your own event listener/observer pattern for it. – MadProgrammer Jan 24 '16 at 23:07
3

Your code does not obey Swing threading rules in that it makes state changes to a Swing application off of the Swing event dispatch thread. I would suggest that you use a SwingWorker for background tasks as well as its publish/process method pair to pass information back to the Swing GUI in a thread-safe manner. If you need to use other methods to create your background thread, then be sure to queue any Swing calls made within your background thread on to the Swing event queue by using something like

SwingUtilities.invokeLater(() -> {
    // swing call here
});
Hovercraft Full Of Eels
  • 283,665
  • 25
  • 256
  • 373