为什么我的计时器不延迟我的代码?我试图延迟我的图形排序以创建我的排序可视化器迭代

Why Doesn't My Timer Delay My Code? I am attemping to delay my graph from sorting to create my iteration of a sorting visualizer

我正在尝试创建一个计时器,它会延迟我的 GUI 对代表随机整数的条形进行排序。这将使排序可见,并且类似于在 YouTube 上看到的样式。我在网上读到 Swing Timers 被推荐用于 GUI,所以我选择了一个。如果你还不知道,这是我的第二个项目,所以如果我的代码看起来很糟糕,请不要向我发送死亡威胁。

无论如何,当 运行 我的代码并按下对图表进行排序的按钮时,尽管有一个定时器被编程为每次延迟 frame.repaint() 调用,但图表会立即排序。再一次,请对我宽容点。这是我第二次在 Whosebug 上提问,我看到有人对忘记分号的人进行恶毒的抨击。让我知道我的 Swing 计时器是否编程错误,或者它是否完全不同

谢谢

主程序

import java.util.Random;
import java.util.Scanner;

public class SortVisualizerShell {
    public static int[] unsortedArray = arrayGenerator();
    public static String requestedSort;

    public static int[] arrayGenerator() {
        int $N = 500;
        int[] array = new int[$N];
        Random rand = new Random();
        for (int i = 0; i < $N; i++) {
            int random_num = rand.nextInt($N);
            array[i] = random_num;
        }
        return array;
    }

    public static void selectionSort(int[] array, int n) {
        for (int i = 0; i < (n - 1); i++) {
            int min = i;
            for (int j = (i + 1); j < n; j++) {
                if (array[min] > array[j]) {
                    min = j;
                }
            }
            int key = array[min];
            while (min > i) {
                array[min] = array[min - 1];
                min = min - 1;
            }
            array[i] = key;
        }
    }

    public static void bubbleSort(int[] array, int n) {
        boolean swapped;
        int i, j, temp;
        for (i = 0; i < (n - 1); i++) {
            swapped = false;
            for (j = 0; j < ((n - 1) - 1); j++) {
                if (array[j] > array[j + 1]) {
                    temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    swapped = true;
                }
            }
            if (swapped == false) {
                break;
            }
        }
    }

    public static void insertionSort(int[] array) {
        int n = array.length;
        for (int i = 1; i < n; i++) {
            int key = array[i];
            int j = i - 1;

            while (j >= 0 && array[j] > key) {
                array[j + 1] = array[j];
                j = j - 1;
            }
            array[j + 1] = key;
        }
    }

    public static void quickSort(int[] array, int left, int right) {
        if (left < right) {
            int pivot = partition(array, left, right);

            quickSort(array, left, pivot - 1);
            quickSort(array, pivot + 1, right);
        }
    }

    public static int partition(int[] array, int low, int high) {
        int pivot = array[high];
        int i = (low - 1);

        for (int j = low; j <= high - 1; j++) {
            if (array[j] < pivot) {
                i++;
                swap(array, i, j);
            }
        }
        swap(array, i + 1, high);
        return (i + 1);
    }

    public static void swap(int[] array, int i, int j) {
        int temp = array[i];
        array[i] = array[j];
        array[j] = temp;
    }

    public static void mergeSort(int[] array, int len) {
        if (len < 2) {
            return;
        }
        int middle = len / 2;
        int[] left_arr = new int[middle];
        int[] right_arr = new int[len - middle];
        int k = 0;
        for (int i = 0; i < len; i++) {
            if (i < middle) {
                left_arr[i] = array[i];
            }
            else {
                right_arr[k] = array[i];
                k = k + 1;
            }
        }
        mergeSort(left_arr, middle);
        mergeSort(right_arr, len - middle);
        merge(left_arr, right_arr, array, middle, (len - middle));
    }

    public static void merge(int[] left_arr, int[] right_arr, int[] array, int left_side,
            int right_side) {
        int i = 0;
        int left = 0;
        int right = 0;
        while (left < left_side && right < right_side) {
            if (left_arr[left] < right_arr[right]) {
                array[i++] = left_arr[left++];
            }
            else {
                array[i++] = right_arr[right++];
            }
        }
        while (left < left_side) {
            array[i++] = left_arr[left++];
        }
        while (right < right_side) {
            array[i++] = right_arr[right++];
        }
    }

    public static void userInputFrame(String requestedSort, int[] array) {
        if (requestedSort.equals("merge sort")) {
            mergeSort(array, array.length);
        }
        else if (requestedSort.equals("quick sort")) {
            quickSort(array, 0, array.length - 1);
        }
        else if (requestedSort.equals("insertion sort")) {
            insertionSort(array);
        }
        else if (requestedSort.equals("bubble sort")) {
            bubbleSort(array, array.length);
        }
        else if (requestedSort.equals("selection sort")) {
            selectionSort(array, array.length);
        }
    }

    public static void activateSort(String requestedSort, int[] unsortedArray) {
        userInputFrame(requestedSort, unsortedArray);
    }

    public static int[] unsort(int[] sortedArray) {
        int[] unsortedArray = arrayGenerator();
        return unsortedArray;
    }

    public static void main(String[] args) {
        Scanner myScanner = new Scanner(System.in);
        System.out.println("Welcome to my sort visualizer");
        System.out.println("");
        System.out.println("Which sort would you like to see in action? ");
        requestedSort = myScanner.nextLine();
        requestedSort = requestedSort.toLowerCase();
        Drawer.createGUI();

        myScanner.close();
    }
}

GUI 程序

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.Box;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Drawer extends JPanel {
    public static SortVisualizerShell sort;
    public static int[] y = SortVisualizerShell.unsortedArray;
    public static String requestedSort;
    public static Timer timer;
    public static int delay = 1000;

    public static void createGUI() {
        JFrame frame = new JFrame();
        JButton sortButton = new JButton("Sort");
        JButton unsortButton = new JButton("Randomize Array");
        JPanel panel = new JPanel();
        Drawer draw = new Drawer();
        requestedSort = SortVisualizerShell.requestedSort;

        panel.setOpaque(false);
        panel.setLayout(new BoxLayout(panel, BoxLayout.PAGE_AXIS));
        panel.add(Box.createRigidArea(new Dimension(0, 5)));
        panel.setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        panel.add(draw);
        panel.add(sortButton);
        panel.add(unsortButton);
        frame.add(panel);

        frame.getContentPane().setBackground(Color.BLACK);
        frame.setVisible(true);
        frame.pack();
        frame.setSize(550, 650);

        sortButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                SortVisualizerShell.activateSort(requestedSort, y);
                frame.repaint();
            }
        });
        unsortButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                y = SortVisualizerShell.unsort(y);
                frame.repaint();
            }
        });
        Timer timer = new Timer(1000, sortButton.getAction());
        timer.setInitialDelay(1000);
        timer.setDelay(1000);
        timer.setRepeats(true);
        timer.start();
    }

    public void paintComponent(Graphics g) {
        for (int i = 0; i < y.length; i++) {
            Graphics2D g2d = (Graphics2D) g;
            g2d.drawRect(i, 0, 5, y[i]);
            g2d.setColor(Color.WHITE);
            g2d.fillRect(i, 0, 5, y[i]);
        }
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                createGUI();
            }
        });
    }
}

首先,关于您问题中的代码需要注意的几点。

  • 您不应将控制台应用程序与 GUI 应用程序混合使用。
    我会添加一个 JComboBox 来选择所需的排序方法。

  • 在代码的下面一行中,sortButton.getAction() returns null.

Timer timer = new Timer(1000, sortButton.getAction());

因此您的计时器基本上什么都不做。

  • 通常重写的 paintComponent 方法的第一行应该是
super.paintComponent(g);

请参阅 Oracle Java 教程中 Creating a GUI With Swing trail 的 Performing Custom Painting 课。


现在我认为您想在所选排序算法的每一步之后执行重绘,以显示排序算法的可视化。在下面的代码中,每个排序算法都是一个单独的 class,每个 class 实现一个 sortStep 方法,该方法在接口 IntsSort.

中声明

我定义了一个enum 对于不同的排序算法。

单击 排序 按钮后,将启动一个 [Swing] timer,它会调用 sortStep 方法每秒选择排序算法。当 sortStep 方法 returns true 表示排序完成时停止计时器。

作为一个额外的视觉辅助,我在排序时将光标设置为 等待 光标 执行并显示 JOptionPane 通知用户排序已终止。

请注意,下面的代码缺少实现合并排序的 classes 和 快速排序。希望你能根据 下面的代码。

IntsSort接口:

/**
 * Sorts array of {@code int}.
 */
public interface IntsSort {

    /**
     * Performs a single, sorting step.
     * 
     * @return  <tt>true</tt> if there are no more sorting steps required indicating that the sort
     *          has completed.
     */
    public boolean sortStep();
}

冒泡排序实现IntsSort:

public class BublSort implements IntsSort {
    private int[]  array;
    private int  i;

    public BublSort(int[] arr) {
        array = arr;
        i = -1;
    }

    @Override
    public boolean sortStep() {
        boolean swapped = false;
        i++;
        if (i < array.length - 1) {
            int temp;
            for (int j = 0; j < ((array.length - 1) - 1); j++) {
                if (array[j] > array[j + 1]) {
                    temp = array[j];
                    array[j] = array[j + 1];
                    array[j + 1] = temp;
                    swapped = true;
                }
            }
        }
        return !swapped;
    }
}

插入排序实现IntsSort:

public class InsrtSrt implements IntsSort {
    private int[]  array;
    private int  i;

    public InsrtSrt(int[] arr) {
        array = arr;
        i = -1;
    }

    public boolean sortStep() {
        boolean stopSorting;
        i++;
        int n = array.length;
        if (i < n) {
            stopSorting = false;
            int key = array[i];
            int j = i - 1;
            while (j >= 0 && array[j] > key) {
                array[j + 1] = array[j];
                j = j - 1;
            }
            array[j + 1] = key;
        }
        else {
            stopSorting = true;
        }
        return stopSorting;
    }
}

接口IntsSort选择排序实现:

public class SlctnSrt implements IntsSort {
    private int[]  array;
    private int  i;

    public SlctnSrt(int[] arr) {
        array = arr;
        i = -1;
    }

    @Override
    public boolean sortStep() {
        boolean stopSorting;
        i++;
        if (i < array.length - 1) {
            stopSorting = false;
            int min = i;
            for (int j = (i + 1); j < array.length; j++) {
                if (array[min] > array[j]) {
                    min = j;
                }
            }
            int key = array[min];
            while (min > i) {
                array[min] = array[min - 1];
                min = min - 1;
            }
            array[i] = key;
        }
        else {
            stopSorting = true;
        }
        return stopSorting;
    }
}

Swing GUI 应用程序:
请注意,randomizeButton 没有 ActionListener,因为我的印象是您已经知道该怎么做。

此外,sortButtonActionListener 使用 method reference

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;

import javax.swing.BorderFactory;
import javax.swing.JButton;
import javax.swing.JComboBox;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.Timer;

public class SortDraw extends JPanel implements Runnable {
    private JComboBox<SortExec.SortMethod>  sortAlgorithmsCombo;
    private JFrame  frame;
    private Timer  timer;

    public SortDraw() {
        setBorder(BorderFactory.createEmptyBorder(10, 10, 10, 10));
        setBackground(Color.darkGray);
        setOpaque(false);
    }

    @Override
    public void run() {
        createAndDisplayGui();
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        int[] y = SortExec.getArray();
        if (y != null) {
            for (int i = 0; i < y.length; i++) {
                Graphics2D g2d = (Graphics2D) g;
                g2d.drawRect(i, 0, 5, y[i]);
                g2d.setColor(Color.WHITE);
                g2d.fillRect(i, 0, 5, y[i]);
            }
        }
    }

    private void createAndDisplayGui() {
        frame = new JFrame("Algos");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.add(createTopPanel(), BorderLayout.PAGE_START);
        frame.add(this, BorderLayout.CENTER);
        frame.add(createButtonsPanel(), BorderLayout.PAGE_END);
        frame.setSize(550, 650);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }

    private JPanel createButtonsPanel() {
        JPanel buttonsPanel = new JPanel();
        JButton sortButton = new JButton("Sort");
        sortButton.setMnemonic(KeyEvent.VK_S);
        sortButton.addActionListener(this::launchSort);
        buttonsPanel.add(sortButton);
        JButton randomizeButton = new JButton("Randomize");
        buttonsPanel.add(randomizeButton);
        return buttonsPanel;
    }

    private JPanel createTopPanel() {
        JPanel topPanel = new JPanel();
        JLabel label = new JLabel("Sort Algorithm");
        topPanel.add(label);
        sortAlgorithmsCombo = new JComboBox<>(SortExec.SortMethod.values());
        topPanel.add(sortAlgorithmsCombo);
        return topPanel;
    }

    private void launchSort(ActionEvent event) {
        SortExec.SortMethod requestedSort = (SortExec.SortMethod) sortAlgorithmsCombo.getSelectedItem();
        setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
        try {
            SortExec.initSort(requestedSort);
        }
        catch (RuntimeException xRuntime) {
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            throw xRuntime;
        }
        timer = new Timer(1000, this::performSort);
        timer.setInitialDelay(0);
        timer.start();
    }

    private void performSort(ActionEvent event) {
        boolean stopSorting = SortExec.performSort();
        repaint();
        if (stopSorting) {
            timer.stop();
            setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
            JOptionPane.showMessageDialog(frame,
                                          "Sorting completed.",
                                          "Complete",
                                          JOptionPane.INFORMATION_MESSAGE);
        }
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(new SortDraw());
    }
}

最后,SortExec 实用程序 class(包括排序算法 enum):

import java.util.Random;

public class SortExec {
    public enum SortMethod {
        BUBBLE, INSERTION, MERGE, QUICK, SELECTION;

        @Override
        public String toString() {
            String str;
            switch (this) {
                case BUBBLE:
                    str = "bubble sort";
                    break;
                case INSERTION:
                    str = "insertion sort";
                    break;
                case MERGE:
                    str = "merge sort";
                    break;
                case QUICK:
                    str = "quick sort";
                    break;
                case SELECTION:
                    str = "selection sort";
                    break;
                default:
                    str = "unknown: " + this.ordinal();
            }
            return str;
        }
    }

    private static int[]  arr;
    private static IntsSort  sorter;

    public static int[] getArray() {
        return arr;
    }

    public static void initSort(SortMethod sortMethod) {
        arr = arrayGenerator();
        sorter = null;
        switch (sortMethod) {
            case BUBBLE:
                sorter = new BublSort(arr);
                break;
            case INSERTION:
                sorter = new InsrtSrt(arr);
                break;
            case SELECTION:
                sorter = new SlctnSrt(arr);
                break;
            default:
                throw new RuntimeException(sortMethod.toString());
        }
    }

    public static boolean performSort() {
        return sorter.sortStep();
    }

    private static int[] arrayGenerator() {
        int $N = 500;
        int[] array = new int[$N];
        Random rand = new Random();
        for (int i = 0; i < $N; i++) {
            int random_num = rand.nextInt($N);
            array[i] = random_num;
        }
        return array;
    }
}