1

所以我正在编写一个使用折线图类型的东西来动画插入排序算法的程序。它现在的编写方式是,当单击填充按钮时,它将生成一个随机整数数组并根据代表线绘制一个 DrawingPanel,当按下暂停按钮时,它会冻结 5 秒,然后显示排序的图形。我想显示每次迭代,一次显示一条移动。有什么建议么。我真的不确定如何在 Java 中使用多线程,我很新。我将不胜感激任何建议。

import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
import javax.swing.*;
import java.util.Random;
import java.util.Arrays;

public class AnimationApplication extends JFrame {

private static final long serialVersionUID = 1L;

AnimationPanel panel1 = new AnimationPanel();
AnimationPanel panel2 = new AnimationPanel();

public static void main(String[] args) {
    AnimationApplication prog = new 
     AnimationApplication("Animation Application");

    prog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    prog.setSize(450, 300);
    prog.setVisible(true);
}

AnimationApplication(String title) {
    super(title);

    setLayout(new BorderLayout());

    add(panel1, BorderLayout.WEST);
    add(panel2, BorderLayout.EAST);
}
}

class AnimationPanel extends JPanel implements ActionListener, Runnable {

private static final long serialVersionUID = 1L;

private int currentSize;

private JButton populate = new JButton("Populate Array");
private JButton pauseB = new JButton("Pause");
private JButton stopB = new JButton("Stop");
private DrawingPanel drawingCanvas = new DrawingPanel();

private volatile Thread animator = null;
private volatile boolean animationSuspended = false;

ArrayList<Integer> pointList = new ArrayList<Integer>();

private Integer [] rndInts;

AnimationPanel() {
    setLayout(new BorderLayout());

    JPanel buttonP = new JPanel(new GridLayout(1, 3, 5, 5));
    buttonP.add(populate);
    buttonP.add(pauseB);
    buttonP.add(stopB);

    populate.addActionListener(this);
    pauseB.addActionListener(this);
    stopB.addActionListener(this);

    add(drawingCanvas, BorderLayout.CENTER);
    add(buttonP, BorderLayout.SOUTH);
}

public void actionPerformed(ActionEvent e) {

    if (e.getSource() == populate) {

                        rndInts = new Integer[ getSize().width-1];


                        for(int i = 0; i < rndInts.length; i++)
  {
    Random rand = new Random();
    rndInts[i]=rand.nextInt((getSize().height)-1);
  //  System.out.println(rndInts[i]);
  }

  currentSize = rndInts.length;               

       pointList = new ArrayList<Integer>(Arrays.asList(rndInts));                



        //System.out.println("Start button pressed");

        // Check if no animation thread exists
        if (animator == null) {

            // If not, start the animation
            start();


        } else {
            // If animation is paused, resume it
            if (animationSuspended) {
                resume();
            }
        }

    } else if (e.getSource() == pauseB) {
        insertionSort(rndInts , currentSize);
        // Check if animation thread exists
        if (animator != null) {

            // If so, suspend the animation thread
            animationSuspended = true;
        }

    } else if (e.getSource() == stopB) {
        stop();
        clear();
    }

}

public void run() {

    Thread thisThread = Thread.currentThread();

    drawingCanvas.repaint();
    while (animator == thisThread) {
        //System.out.println("Animation thread running");
      drawingCanvas.repaint();
        try {
          //  Thread.sleep(1);
 drawingCanvas.repaint();
            if (animationSuspended) {
                synchronized (this) {
                    while (animationSuspended && animator == thisThread) {
                        drawingCanvas.repaint();
                        wait();
                        drawingCanvas.repaint();
                    }
                }
            }
        } catch (InterruptedException e) {
            break;
        }

        // Repaint the panel
        drawingCanvas.repaint();
    }

}

public void start() {
drawingCanvas.repaint();
    // Create a new animation thread and start it
    animator = new Thread(this);
    animationSuspended = false;
    animator.start();
    animationSuspended = true;
 }




public synchronized void stop() {
    drawingCanvas.repaint();
    animator = null;
    notify();
}

public synchronized void resume() {
    animationSuspended = false;
    notify();
}

public void clear() {
    pointList.clear();
    repaint();
}


void insertionSort(Integer [] arr, int length) 
{
  int i, j, tmp;
  for (i = 1; i < length; i++) 
{
        j = i;
        while (j > 0 && arr[j - 1] > arr[j]) 
{
              tmp = arr[j];
              arr[j] = arr[j - 1];
              arr[j - 1] = tmp;
              j--;
              stop();
              drawingCanvas.repaint();
              start();
              //resume();
        }

  }
}



class DrawingPanel extends JPanel implements Runnable {

    private static final long serialVersionUID = 1L;

    protected void paintComponent(Graphics g) {





        // Call superclass version of method
        super.paintComponent(g);

        this.setBackground(Color.WHITE);

        //clear the background
        g.clearRect(0, 0, getSize().width-1, getSize().height-1);

        g.setColor(Color.RED);



        // Draw points
        for (int i = 0; i < currentSize ; i++) //pointList.size(); i++) 
        {
          g.drawLine(i, getSize().height, i, rndInts[i]);
          repaint();
            //resume(); 
        }
      }
    }

}
4

2 回答 2

0

一些建议:

1.)您不需要(更具体地说,不想要)多线程(线程)。

2.) 所有对 Swing 方法的访问(我认为除了repaint)都必须在事件队列中。(实际上,根据个人经验,Swing 在 99.999% 的情况下都可以在 EventQueue 中正常工作,但那 0.001% 是谋杀!)即使没有线程,您的main方法也不在事件队列上,所以开始这样的事情:

EventQueue.InvokeLater( new Runnable()  {
    AnimationApplication prog = new AnimationApplication( "Animation Application" );
    prog.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    prog.setSize(450, 300);
    prog.setVisible(true);
} );

3.) 使用 Swing 计时器让您完成每一步。使用“填充”按钮启动它并使用“暂停”按钮暂停它(如果可以,请停止并重新创建它,如果你不能,我有一段时间没有使用它而且我的记忆力很差)。Swing 计时器与您可以使用的任何其他东西(例如 AWT 计时器)不同,它在 EventQueue 上运行其事件。

4.) 编写一个方法来完成其中的一个步骤。然后在每个计时器事件中调用它一次,因此在每个事件中您执行排序步骤,然后更新显示。

更一般地说,你必须让你的显示工作关闭 UI 事件——按钮按下和计时器事件——而不是当前排序代码的进度。你的排序需要从里到外翻过来,就像 UI 的曲调一样,而不是尽可能快地进行排序。这些天的代码执行速度太快,一个线程无法观察另一个线程在做什么。

于 2013-07-26T16:22:21.120 回答
0
void insertionSort(Integer[] arr, int length) {
        int i, j, tmp;
        for (i = 1; i < length; i++) {
            j = i;
            while (j > 0 && arr[j - 1] > arr[j]) {
                tmp = arr[j];
                arr[j] = arr[j - 1];
                arr[j - 1] = tmp;
                j--;
                stop();
                drawingCanvas.repaint();
                start();
                // resume();
            }

        }
    }

我认为这段代码是问题所在,在一个循环start();中被多次调用。请调试并找出如何重构。

于 2013-07-26T04:29:44.810 回答