JavaFX可视化算法的条形图与动画



所以我真的被困在这一个,我需要输出的算法是在我的代码底部到JavaFX,显示算法是如何工作的,即冒泡排序移动较小的酒吧对前面等问题,我所拥有的是,我无法弄清楚如何让我的算法在JavaFX正确显示。交换一半和随机工作但我没有工作的那部分代码或上面的部分所以我仍然在黑暗中,我仍然是java的新手和JavaFX对我来说有点奇怪的时刻

import javafx.application.Application;
import javafx.application.Platform;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import static javafx.scene.chart.XYChart.*;
import javafx.geometry.Insets;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Random;
public class hamrickP2 extends Application {
public static void main(String[] args) {
    hamrickP2.launch(args);
}
private static final int
    BAR_COUNT = 14,
    MAX_BAR_HEIGHT = 50;
private static final String
    COLOR_ACTIVE = "-fx-bar-fill: #f64",
    COLOR_INITIAL = "-fx-bar-fill: #888",
    COLOR_FINALIZED = "-fx-bar-fill: #3cf";
private static final int
    DELAY_MILLIS = 700;
@Override
public void start(Stage stage) {
    stage.setTitle("Sorting Animations");
    stage.setWidth(800);
    stage.setHeight(600);
    final BorderPane pane = new BorderPane();
    pane.setPadding(new Insets(10));
    final BarChart<String,Number> chart = new BarChart<>(new      CategoryAxis(), new NumberAxis(0, MAX_BAR_HEIGHT, 0));
    chart.setLegendVisible(false);
    chart.getYAxis().setTickLabelsVisible(false);
    chart.getYAxis().setOpacity(0);
    chart.getXAxis().setTickLabelsVisible(false);
    chart.getXAxis().setOpacity(0);
    chart.setHorizontalGridLinesVisible(false);
    chart.setVerticalGridLinesVisible(false);
    bars = new ArrayList<Data<String,Number>>();
    final Series<String,Number> data = new Series<>();
    chart.getData().add(data);
    for (int i = 0; i < BAR_COUNT; i++) {
        bars.add(new Data<>(Integer.toString(i+1), 1));
        data.getData().add(bars.get(i));
        paint(i, COLOR_INITIAL);
    }
    pane.setCenter(chart);
    inputs = new FlowPane();
    inputs.setHgap(5);
    inputs.setVgap(5);
    createButton("Randomize", () -> randomizeAll());
    createButton("Swap Halves", () -> swapHalves());
    createButton("Reverse ", () -> reverse()); 
    createButton("Selection Sort", () -> selectionSort());

    pane.setBottom(inputs);
    stage.setScene(new Scene(pane));
    stage.show();
    Platform.runLater(() -> randomizeAll());
}
    private ArrayList<Data<String,Number>> bars;
    private FlowPane inputs;
    private void createButton(String label, Runnable method) {
    final Button test = new Button(label);
    test.setOnAction(event -> new Thread(() -> {
        Platform.runLater(() -> inputs.setDisable(true));
        method.run();
        Platform.runLater(() -> inputs.setDisable(false));
    }).start());
    inputs.getChildren().add(test);
}

// CHART ACCESSORS AND MUTATORS
private void assign(int index, int value) {
    bars.get(index).setYValue(value);
}
private int retrieve(int index) {
    return (int) bars.get(index).getYValue();
}
// ANIMATION CONTROLS
private void paint(int index, final String style) {
    Platform.runLater(() -> {
        bars.get(index).getNode().setStyle(style);
    });
}
private void paintAll(final String style) {
    Platform.runLater(() -> {
        for (int i = 0; i < BAR_COUNT; i++) paint(i, style);
    });
}
private void delay() {
    try {
        Thread.sleep(DELAY_MILLIS);
    }
    catch (InterruptedException e) {
        e.printStackTrace();
    }
}
// ALGORITHMS FOR BUTTONS
private void randomizeAll() {
    Random random = new Random();
    for (int i = 0; i < BAR_COUNT; i++) {
        assign(i, random.nextInt(MAX_BAR_HEIGHT) + 1);
    }
}
private void swapHalves() {
    final int half = bars.size()/2;
    final int offset = bars.size() % 2;
    for (int i = 0; i < half; i++) {
        final int j = i + half + offset;
        paint(i, COLOR_ACTIVE);
        paint(j, COLOR_ACTIVE);
        int temp = retrieve(i);
        assign(i, retrieve(j));
        assign(j, temp);
        delay();
        paint(i, COLOR_FINALIZED);
        paint(j, COLOR_FINALIZED);
    }
    paintAll(COLOR_INITIAL);
}// Start of algorithms 
/**
 * Reverse algorithm 
 * @param array
 * @return
 */
public void reverse(){
    int array [] = new int [BAR_COUNT];
    for(int pos = 0; pos < array.length; pos++)
    {
        int generic = array[pos];
        array[pos] = array[array.length - 1 - pos];
        array[array.length -1 - pos] = generic;
        int temp = array[array.length -1 - pos];
        assign(array[pos] , retrieve(array[array.length - 1 - pos]));
        assign(temp , generic);
        delay();

        paint(pos, COLOR_FINALIZED);
        paint( temp, COLOR_FINALIZED);

    }
    paintAll(COLOR_INITIAL);
}

/**
 * Selection Sort algorithm
 * @param words
 */
public  void selectionSort(){
    int arr [] = new int [BAR_COUNT];
    for (int i = 0; i < arr.length - 1; i++)
    {
        paint(i, COLOR_ACTIVE);
        int index = i;
        for (int j = i + 1; j < arr.length; j++)
            if (arr[j] < arr[index]) 
                index = j;
        int smallerNumber = arr[index];  
        arr[index] = arr[i];
        arr[i] = smallerNumber;
        int temp = retrieve(i);
        assign(i, retrieve(i));
        assign(index, temp);
        delay();
        paint(i, COLOR_FINALIZED);
        paint(index, COLOR_FINALIZED);
    }
    paintAll(COLOR_INITIAL);
}
        /**
         * Bubble Sort algorithm
         * @param words
         */
        public  void bubbleSort(){
            int array [] = new int [BAR_COUNT];
            int temp;
            for(int i = 0; i <array.length; i++){
                for(int j = 1; j <array.length -i; j++){
                    if(array[j-1] > array[j]){
                        temp = array[j -1];
                        array[j-1] = array[j];
                        array[j] = temp;
                    }
                }
            }
        }
                    /**
             * Insertion Sort algorithm
             * @param array
             */
    public  void insertionSort (){
        int array [] = new int [BAR_COUNT];
        for (int i = 1; i < array.length; i++) {
            int temp = array[i];
            int j;
            for(j = i -1; j>= 0 && temp < array[j]; j--){
                array[j +1 ] = array[j];
            array[j + 1 ] =temp;
        }
            paintAll(COLOR_INITIAL);    
    }
}
}

我在你的代码中发现了一些问题。请考虑以下事项:

  1. bars设置为ObservableList,并将其用于您的系列。Series实例将获取此列表并在内部使用它。这样,当图表自动更新时,您将能够观察列表并稍后修改列表。访问数据就像使用bar作为列表或从bar中提取数组一样简单。我做了两个泡泡排序版本。一个访问栏作为列表(已就位),另一个提取数组(未就位)。
  2. 在向条形图中添加新的Data对象后,您将能够访问节点以更改颜色。不需要使用Platform.runlater。无论如何,Runlate都会被误用,因为无法保证您正在等待的资源会在稍后的时间点出现。如果你想对一个未知时间点存在的资源做一些操作,如果它是一个可观察值,请观察它。使用addListener并观察变化。
  3. 不要使用线程并在其中修改GUI中的数据。使用runlater来禁用按钮是可以的,但是你在线程中做了很多其他的事情。此外,您的runlater的主体可能稍后调用(O.o .)。这么久之后,你的线程已经完成了。Runlater是一个异步调用。
  4. 如果你想在预定的时间框架内修改gui,使用JavaFX动画类。时间线也许就是你要找的。本教程介绍这个概念。

我从你的代码做了一个例子。我删除了一些东西,使它更清楚:

import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.BarChart;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.control.Button;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.stage.Stage;
import java.util.List;
import java.util.Random;
import static javafx.scene.chart.XYChart.Data;
import static javafx.scene.chart.XYChart.Series;
public class Main extends Application {
    public static void main(String[] args) {
        launch(args);
    }
    private static final int
        BAR_COUNT = 14,
        MAX_BAR_HEIGHT = 50;
    private static final String
        COLOR_ACTIVE = "-fx-bar-fill: #f64",
        COLOR_INITIAL = "-fx-bar-fill: #888",
        COLOR_FINALIZED = "-fx-bar-fill: #3cf";
    private static final int
        DELAY_MILLIS = 700;

    private ObservableList<Data<String, Number>> bars;
    private BarChart<String, Number> chart;
    private FlowPane inputs;

    @Override
    public void start(Stage stage) {
        stage.setTitle("Sorting Animations");
        stage.setWidth(800);
        stage.setHeight(600);
        final BorderPane pane = new BorderPane();
        pane.setPadding(new Insets(10));
        makeChart(pane);
        makeButtons(pane);
        stage.setScene(new Scene(pane));
        stage.show();
        randomizeAll();
    }
    private void makeChart(BorderPane pane) {
        chart = new BarChart<>(new CategoryAxis(), new NumberAxis(0, MAX_BAR_HEIGHT, 0));
        chart.setLegendVisible(false);
        chart.getYAxis().setTickLabelsVisible(false);
        chart.getYAxis().setOpacity(0);
        chart.getXAxis().setTickLabelsVisible(false);
        chart.getXAxis().setOpacity(0);
        chart.setHorizontalGridLinesVisible(false);
        chart.setVerticalGridLinesVisible(false);
        bars = FXCollections.observableArrayList();
        chart.getData().add(new Series<>(bars));
        for (int i = 0; i < BAR_COUNT; i++) {
            Data<String, Number> dataObject = new Data<>(Integer.toString(i + 1), 1);
            bars.add(dataObject); // node will be present after this
            addPainting(dataObject.getNode(), COLOR_INITIAL); // do this after bars.add
        }
        pane.setCenter(chart);
    }

    private void makeButtons(BorderPane pane) {
        inputs = new FlowPane();
        inputs.setHgap(5);
        inputs.setVgap(5);
        createButton("Randomize", () -> randomizeAll());
        createButton("Bubble Sort 1", () -> bubbleSort1());
        createButton("Bubble Sort 2", () -> bubbleSort2());
        pane.setBottom(inputs);
    }
    private void addPainting(Node newNode, String colorInitial) {
        if (newNode != null) {
            newNode.setStyle(colorInitial);
        }
    }
    private void createButton(String label, Runnable method) {
        final Button test = new Button(label);
        test.setOnAction(event -> method.run());
        inputs.getChildren().add(test);
    }

    private void randomizeAll() {
        Random random = new Random();
        for (Data<String, Number> bar : bars) {
            bar.setYValue(random.nextInt(MAX_BAR_HEIGHT) + 1);
        }
    }

    /**
     * Bubble Sort algorithm
     */
    private void bubbleSort1(){
        List<Data<String, Number>> list = bars;
        double temp;        
        for(int i = 0; i < list.size(); i++){
            for(int j = 1; j < list.size() - i; j++){
                if (getValue(list, j - 1) > getValue(list, j)){
                    temp = getValue(list, j - 1);
                    list.get(j - 1).setYValue(list.get(j).getYValue());
                    list.get(j).setYValue(temp);
                }
            }
        }
    }
    private double getValue(List<Data<String, Number>> list, int index) {
        return list.get(index).getYValue().doubleValue();
    }

    /**
     * Bubble Sort algorithm
     */
    private void bubbleSort2(){
        double[] array = bars.stream().mapToDouble(data -> data.getYValue().doubleValue()).toArray();
        double temp;
        for(int i = 0; i <array.length; i++){
            for(int j = 1; j <array.length -i; j++){
                if(array[j-1] > array[j]){
                    temp = array[j -1];
                    array[j-1] = array[j];
                    array[j] = temp;
                }
            }
        }
        for (int i = 0; i < array.length; i++) {
            bars.get(i).setYValue(array[i]);
        }
    }
}

更新1 如果你以可观察的方式实现它,就像你在问题中已经做过的那样分配和检索工作。

private void assign(int index, int value) {
    bars.get(index).setYValue(value);
}
private int retrieve(int index) {
    return (int) bars.get(index).getYValue();
}

我用了同样的方法;例如,参见最后一个for循环的主体。

要使图表动画化,你必须重写算法,以便每次调用只进行一步,而不是一次对整个数组进行排序。如。对bubblesort的函数调用在它进行第一次交换后返回。

最后一步是初始化一个TimeLine (Timer),以便每t秒调用一次仅一步的冒泡排序算法。

最棘手的部分是如何记住算法的最后一次运行在哪里停止以及如何继续运行。

最新更新