-1

This is a bubble sort algorithm visualization code. I want rectangles to be swapped. However, I couldn't make it. When I run the program it waits a bit, max 2 seconds, then all rectangles are moving and it lasts 1 seconds or something. The problem is thread I guess, what should I do?

public void bubbleSort(Rectangle[] rectangles) throws InterruptedException {
        int pass = 1;
            for(int j = 0; j < rectangles.length-1; j++) {
                for (int i = 0; i < rectangles.length - 1-j; i++) {
                    int pos = i;
                    if (rectangles[i].getHeight() > rectangles[i + 1].getHeight()) {

                        Runnable task = new Runnable() {
                            @Override
                            public void run() {
                                try {
                                    System.out.println("opıjapısdjapsoıdj");
                                    Platform.runLater(new Runnable() {
                                        @Override
                                        public void run() {
                                            createAnimation(pos, pos + 1);
                                            System.out.println("xxxxxxx");
                                        }
                                    });
                                    Thread.sleep(2000);
                                } catch (InterruptedException exception) {
                                    // nothing
                                }
                            }
                        };
                        new Thread(task).start();

                        Rectangle temp = rectangles[i];
                        rectangles[i] = rectangles[i + 1];
                        rectangles[i + 1] = temp;
                    }
                }
            }
    }
  • You have no delay between tasks. The tasks themselves have a delay, but that delay is local to each task only. Not to mention the delay is _after_ you schedule the action with the FX thread (i.e. `runLater`). Using threads for this is probably overkill and more trouble than it's worth, anyway. – Slaw Jan 28 '20 at 12:07
  • 2
    Break down your sorting algorithm into discrete (yet repeatable) steps. Then [use the animation API to periodically execute](https://stackoverflow.com/a/9966213/6395627) the next step in the algorithm. When that step completes the UI should update to reflect the new state. Now the algorithm is paused until the next step is executed. This continues until the algorithm completes. See [event-driven programming](https://en.wikipedia.org/wiki/Event-driven_programming) and the [state pattern](https://en.wikipedia.org/wiki/State_pattern). – Slaw Jan 28 '20 at 12:07
  • 1
    please don't re-post the same question .. instead edit the old to include details as needed (in particular a [mcve]) – kleopatra Jan 28 '20 at 12:24
  • I would follow @Slaw advice. First I would create a List of List that holds each state of the sorting. I would then use the `Timeline` from the `Animation` API to show a different state every second. – SedJ601 Jan 28 '20 at 15:14
  • Does this answer your question? [Dynamic Bar chart in Java FX](https://stackoverflow.com/questions/53573747/dynamic-bar-chart-in-java-fx) – SedJ601 Jan 28 '20 at 15:16

1 Answers1

1

Long running code should never be put on the JavaFX Application Thread, as this will cause your GUI to freeze and become unresponsive.

In simple situations, you can use:

Executors.newSingleThreadExecutor().execute(() -> doComputation());

to post a job to a different thread and:

Platform.runLater(() -> updateDisplay());

to post a GUI update to the Application Thread.

However, a more reccomended solution is to use a Service.

This is a class that you can extend, and provide a createTask() method, which you can then asynchronously call and listen for responses.

For example:

public class SortService extends Service<int[]> {

    private int[] array;

    public void sortArray(int[] array) {
        this.array = array;
        restart();  // restart() restarts the service regardless of its status
    }

    @Override
    public Task<int[]> createTask() {
        return new Task<int[]> {
            @Override
            protected int[] call() throws Exception {
                // do your sorting and then return the result
                return sortedArray;
            }

        }
    }
}

Once you have this class setup, you can create an instance, set the array, and listen for results.

SortService service = new SortService();
service.valueProperty().addListener((obs, oldValue, newValue) -> {
    // run on JavaFX Application Thread, safe to update GUI

    System.out.println("Hello from JavaFX Application Thread");
    System.out.println(Arrays.toString(newValue));  
// newValue is our sorted int[] (it is the value you return in your service's createTask())
});
service.sortArray(Arrays.asList(1, 2, 5, 4, 3));  // launch the service

If you want to change the value during the running of your Service, before you return, you can call updateValue(newValue) (perhaps you want to display every stage of the sort instead of just the final output).

cameron1024
  • 9,083
  • 2
  • 16
  • 36