[英]Multithreading Sort Animation in Java
因此,我正在编写一个使用折线图类型的东西对插入排序算法进行动画处理的程序。 现在的编写方式是,它会生成一个随机整数数组,并在单击填充按钮时根据绘制代表性的线条绘制一个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();
}
}
}
}
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();
被打了几次。 请调试并了解如何重构。
一些建议:
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计时器让您执行每个步骤。 用“填充”按钮启动它,然后用“暂停”按钮暂停它(如果可以,停止它,然后重新创建它,我已经有一段时间没用了,我的记忆不好)。 与您可以使用的任何其他计时器(例如AWT计时器)不同,Swing计时器在EventQueue上运行其事件。
4.)编写一个执行排序步骤的方法。 然后在每个计时器事件中调用一次,因此在每个事件内您执行排序的一个步骤,然后更新显示。
更一般而言,您必须使显示工作脱离UI事件(按钮按下和计时器事件),而不是当前排序代码的进度。 您的排序需要像原来那样由内而外地跳动,以适应UI的调音,而不是快速进行排序以实现最快的排序。 这些天的代码执行速度太快,以至于一个线程无法观察另一个线程在做什么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.