且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

Java Swing 计算时重绘:动画排序算法

更新时间:2023-02-06 08:28:38

注意:我在问题被删除之前开始写这个

很可能您使用了一些循环机制并祈祷每次迭代,ui 都会更新.这是一个错误的假设.在循环完成之前,用户界面将不会更新.你正在做的是我们所说的阻塞事件调度线程(EDT)

Most likely your using some looping mechanism and praying that each iteration, the ui with be updated. That's a wrong assumption. The UI will not be update until the loop is finished. What you are doing is what we refer to as blocking the Event Dispatch Thread(EDT)

请参阅如何使用 Swing 计时器.在 ActionListener 回调中进行迭代" 更新.例如,如果您想为排序算法设置动画,您需要确定每次计时器回调的迭代" 需要更新什么.然后每次迭代都重新绘制 ui.

See How to use a Swing Timer. Make "iterative" updates in the ActionListener call back. For instance, if you want to animate a sorting algorithm, you need to determine what needs to be updated per "iteration" of the timer callback. Then each iteration repaint the ui.

所以你的定时器可能看起来像

So your Timer timer could look something like

Timer timer  = new Timer(40, new ActionListener(){
    @Override
    public void actionPerformed(ActionEvent e) {
        if (sortingIsDone()) {
            ((Timer)e.getSource()).stop();
        } else {
            sortOnlyOneItem();
        }
        repaint();
    }
});

您的 sortOnlyOneItem 方法应该只对一个项目执行排序.并有某种标志来检查排序是否完成,然后停止计时器.

Your sortOnlyOneItem method should only, well, perform a sort for just one item. And have some sort of flag to check if the sorting is done, then stop the timer.

其他注意事项:

  • 如果您不打算自己绘制背景,则应该在 paintComponent 方法中调用 super.paintComponent.不过一般我总是这样做.
  • You should be calling super.paintComponent in the paintComponent method, if you aren't going to paint the background yourself. Generally I always do though.

这是一个完整的例子.我很高兴你自己想通了.在我看到你得到它之前,我正在研究这个例子.

Here's a complete example. I'm glad you figured it out on your own. I was working on this example before I saw that you got it.

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Collections;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import javax.swing.Timer;

public class SelectionSortAnimate extends JPanel {

    private static final int NUM_OF_ITEMS = 20;
    private static final int DIM_W = 400;
    private static final int DIM_H = 400;
    private static final int HORIZON = 350;
    private static final int VERT_INC = 15;
    private static final int HOR_INC = DIM_W / NUM_OF_ITEMS;

    private JButton startButton;
    private Timer timer = null;
    private JButton resetButton;

    Integer[] list;
    int currentIndex = NUM_OF_ITEMS - 1;

    public SelectionSortAnimate() {
        list = initList();

        timer = new Timer(200, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                if (isSortingDone()) {
                    ((Timer) e.getSource()).stop();
                    startButton.setEnabled(false);
                } else {
                    sortOnlyOneItem();
                }
                repaint();
            }
        });
        startButton = new JButton("Start");
        startButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                timer.start();
            }
        });
        resetButton = new JButton("Reset");
        resetButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                list = initList();
                currentIndex = NUM_OF_ITEMS - 1;
                repaint();
                startButton.setEnabled(true);
            }
        });
        add(startButton);
        add(resetButton);
    }

    public boolean isSortingDone() {
        return currentIndex == 0;
    }

    public Integer[] initList() {
        Integer[] nums = new Integer[NUM_OF_ITEMS];
        for (int i = 1; i <= nums.length; i++) {
            nums[i - 1] = i;
        }
        Collections.shuffle(Arrays.asList(nums));
        return nums;
    }

    public void drawItem(Graphics g, int item, int index) {
        int height = item * VERT_INC;
        int y = HORIZON - height;
        int x = index * HOR_INC;
        g.fillRect(x, y, HOR_INC, height);
    }

    public void sortOnlyOneItem() {
        int currentMax = list[0];
        int currentMaxIndex = 0;

        for (int j = 1; j <= currentIndex; j++) {
            if (currentMax < list[j]) {
                currentMax = list[j];
                currentMaxIndex = j;
            }
        }

        if (currentMaxIndex != currentIndex) {
            list[currentMaxIndex] = list[currentIndex];
            list[currentIndex] = currentMax;
        }
        currentIndex--;
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (int i = 0; i < list.length; i++) {
            drawItem(g, list[i], i);
        }
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(DIM_W, DIM_H);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame("Sort");
                frame.add(new SelectionSortAnimate());
                frame.pack();
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }
}