2013-03-28 4 views
1

Для моего класса алгоритмов наше назначение состоит в том, чтобы выполнить mergesort на массиве и показать, что происходит как анимация. У меня есть код (теоретически), но когда я вызываю repaint() много раз быстро (для анимации массива), они игнорируются. Никакая анимация не отображается, а только последний массив. Должно быть одно «-» после каждого «*» на консоли, но это не так, существует много «*» (как и должно быть), но только один «-». «*» Обозначает, когда должен быть вызван метод repaint, а символ «-» обозначает, когда он на самом деле вызван.Вызов Java multiple 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

Ваша сортировка слияние происходит быстрее, чем вы думаете, и перерисовки будут называться так близко друг к другу, что они получают «уложены», и когда это происходит, да, они могут получить игнорируются. Даже если они не игнорируются, снова скорость кода приведет к отсутствию видимых изменений в графическом интерфейсе, и даже если процесс займет много времени, графический интерфейс будет заблокирован, поскольку поток событий Swing будет слишком занят рисованием.

Решение заключается в том, чтобы замедлить работу вашего кода, но не с Thread.sleep(...), который снова свяжет поток событий Swing, если он не вызван в фоновом потоке, а скорее с помощью таймера Swing. Это позволит коду продвигаться медленнее пошаговым способом, но не связывая поток событий Swing.

+0

Хорошо, спасибо. Я только запускаю таймер, где я в настоящее время вызываю перерисовку в методе mergesort, а затем, когда он отключается, перезагрузите его? – zr870

+0

@ ZR870: нет, вам придется изменить свою логику, чтобы использовать таймер. Действие ActionListener Timer ActionPerformed будет вызываться повторно вместо цикла. Это потребует реорганизации совсем немного. –

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(); 
    } 
}