2013-03-28 56 views
1

對於我的算法類,我們的任務是在數組上執行mergesort並顯示動畫發生的事情。我有代碼(理論上)工作,但是當我快速調用repaint()多次(爲數組設置動畫)時,它們會被忽略。沒有動畫顯示,只是最後一個數組。在控制檯的每個'*'之後應該有一個' - ',但事實並非如此,有很多'*'(應該是),但只有一個' - '。 '*'表示何時應該調用repaint方法,' - '表示何時調用它。Java多重repaint()調用被忽略

package a2; 

import java.awt.BorderLayout; 
import java.awt.Color; 
import java.awt.Graphics; 
import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.Arrays; 
import java.util.Random; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JOptionPane; 
import javax.swing.JPanel; 

public class GraphicalSort extends JFrame implements ActionListener { 
    int[] data = new int[200]; 
    int[] helper = new int[200]; 
    JPanel panel = new JPanel(); //Panel to hold graphical display of array 
    JPanel buttonsPanel = new JPanel(); 
    JButton mButton = new JButton("Mergesort"); 
    JButton sButton = new JButton("Scramble"); 

    //Constants to scale the width and height 
    int barWidth = 8; 
    int barHeight = 1; 

    public GraphicalSort() { 
     setLayout(new BorderLayout()); 
     mButton.addActionListener(this); 
     sButton.addActionListener(this); 
     buttonsPanel.add(sButton); 
     buttonsPanel.add(mButton); 
     for (int i = 0; i < data.length; i++) { 
      data[i] = (int) (500 * Math.random() + 1); 
      helper[i] = data[i]; 
     } 
     setSize(barWidth * data.length, barHeight * 500 + buttonsPanel.getHeight()); 
     panel = new ArrayPanel(); 
     add(buttonsPanel, BorderLayout.NORTH); 
     add(panel, BorderLayout.CENTER); 

     repaint(); 
     validate(); 
    } 

    public static void main(String[] args) { 
     GraphicalSort gs = new GraphicalSort(); 
     gs.setTitle("Graphical Sort"); 
     gs.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     gs.setLocationRelativeTo(null); 
     gs.setResizable(false); 
     gs.setVisible(true); 
    } 

    @SuppressWarnings("serial") 
    class ArrayPanel extends JPanel { 
     public void paintComponent(Graphics g) { 
      super.paintComponent(g); 
      g.setColor(Color.BLACK); 
      System.out.println("-"); //when repaint is actually called 
      int xPos = 0; 
      for (int i = 0; i < data.length; i++) { 
       g.fillRect(xPos, (barHeight * 500) - (barHeight * data[i]), barWidth, barHeight * data[i]); 
       xPos += barWidth; 
      } 
     } 
    } 

    @Override 
    public void actionPerformed(ActionEvent e) { 
     if (e.getSource() == mButton) { 
      mergesort(0, data.length - 1); 
     } else if (e.getSource() == sButton) { 
      Random r = new Random(); 
      for (int i = 0; i < data.length; i++) { 
       int index = r.nextInt(data.length); 
       int temp = data[i]; 
       data[i] = data[index]; 
       data[index] = temp; 
       panel.repaint(); 
      } 
     } 
    } 

    private void mergesort(int low, int high) { 
     // Check if low is smaller then high, if not then the array is sorted 
     if (low < high) { 
      // Get the index of the element which is in the middle 
      int middle = (low + high)/2; 
      // Sort the left side of the array 
      mergesort(low, middle); 
      // Sort the right side of the array 
      mergesort(middle + 1, high); 
      // Combine them both 
      merge(low, middle, high); 
      System.out.println("*"); //When the repaint should be called 
      panel.repaint(); 
     } 
    } 

    private void merge(int low, int middle, int high) { 

     // Copy both parts into the helper array 
     for (int i = low; i <= high; i++) { 
      helper[i] = data[i]; 
     }  

     int i = low; 
     int j = middle + 1; 
     int k = low; 
     // Copy the smallest values from either the left or the right side back 
     // to the original array 
     while (i <= middle && j <= high) { 
      if (helper[i] <= helper[j]) { 
       data[k] = helper[i]; 
       i++; 
      } else { 
       data[k] = helper[j]; 
       j++; 
      } 
      k++; 
     } 
     // Copy the rest of the left side of the array into the target array 
     while (i <= middle) { 
      data[k] = helper[i]; 
      k++; 
      i++; 
     } 

    } 
}  

回答

1

比你認爲你的歸併排序正在發生快速和重繪被稱爲如此接近,它們一起得到「堆積」,當出現這種情況,是的,他們可以被忽略。即使它們沒有被忽略,代碼的速度再也不會導致GUI的可見變化,並且即使該過程確實花費了大量時間,GUI也將被鎖定,因爲Swing事件線程也將被鎖定忙着畫畫。

解決方法是放慢代碼,但不會與Thread.sleep(...)再次合併Swing事件線程(如果未在後臺線程中調用),而是使用Swing Timer。這將允許代碼以更慢的步進方式進行,但不捆綁Swing事件線程。

+0

好的,謝謝。我是否剛剛啓動計時器,我正在調用mergesort方法中的repaint,然後在它關閉時重置它? – zr870 2013-03-28 02:05:03

+0

@ ZR870:不,你必須改變你的邏輯來使用定時器。定時器的ActionListener的actionPerformed將被重複調用以代替循環。這需要重構很多。 – 2013-03-28 02:10:32

0

要在「爭奪」期間看到動畫,您可以使用以下內容替換您的動作預執行方法。可以選擇添加代碼來限制一次加擾到一個加擾。

public void actionPerformed(final ActionEvent e) { 
    if (e.getSource() == mButton) { 
     mergesort(0, data.length - 1); 
    } else if (e.getSource() == sButton) { 
     new Thread(new Runnable() { 
      public void run() { 
       final Random r = new Random(); 
       for (int i = 0; i < data.length; i++) { 
        try {Thread.sleep(10);} 
        catch (final InterruptedException e) 
        { e.printStackTrace(); } 
        final int index = r.nextInt(data.length); 
        final int temp = data[i]; 
        data[i] = data[index]; 
        data[index] = temp; 
        panel.repaint(); 
       } 
      } 
     }).start(); 
    } 
}