Перерисовка Java swing во время вычислений: анимация алгоритма сортировки

#java #swing #sorting #animation #event-dispatch-thread

#java #swing #сортировка #Анимация #событие-отправка-поток

Вопрос:

http://www.youtube.com/watch?v=M0cNsmjK33E

Я хочу разработать что-то похожее на ссылку выше, используя Java Swing. У меня есть метод сортировки, и я перерисовал его во время перерисовки, но когда я запустил сортировку, вместо того, чтобы показывать, что столбцы медленно сортируются сами по себе, он зависает, а затем размораживается, когда массив был полностью отсортирован.

Как мне это исправить? Редактировать: извините, забыл о кодах. это очень простой графический интерфейс. и другой класс для сортировки, который сортирует весь массив

 public class SortGUI {
JFrame frame;
int frameWidth = 1000, frameHeight = 1000;
int panelWidth, panelHeight;
DrawPanel panel;
JPanel panel2;
JScrollPane scroll;
JViewport view;

static int[] S = new int[50000];

public static void main(String[] args) throws InterruptedException {
    SortGUI app = new SortGUI();
    initializeArray();        
    app.go(); 
}

public static void initializeArray()
{
         for (int i = 0; i < S.length; i  ) {
     S[i] = (int) (Math.random() * 16581375);
     }
}

public void go() throws InterruptedException {
    //Frame
    frame = new JFrame();
    frame.setSize(frameWidth, frameHeight);
    frame.setVisible(true); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  

    //panel
    panel = new DrawPanel();
    scroll = new JScrollPane(panel,JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED, JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);


    //Layout
    frame.add(scroll);
    frame.addKeyListener(new keyListener());

    while(true)
    {               
        panel.repaint();
    }
   }


public class DrawPanel extends JPanel
{   
    public DrawPanel()
    {
        this.setPreferredSize(new Dimension(50000,930));
    }

    public void paintComponent(Graphics g) 
    {          
        g.setColor(Color.WHITE);
        g.fillRect(0, 0, this.getWidth(), this.getHeight());
        for(int i = 0; i < S.length; i  )
        {
            int red = S[i] / 65025;
            int green = (S[i] > 65025)? S[i] % 65025 : 0;
            int blue = green;
            blue %= 255;
            green /= 255;

             g.setColor(new Color(red,green,blue));
            g.fillRect(i, 900 - (S[i] / 18500), 1, S[i] / 18500);
        }
    }
}

  public class keyListener implements KeyListener{


    public void keyTyped(KeyEvent ke) {

    }


    public void keyPressed(KeyEvent ke) {
      if(ke.getKeyChar() == '1')
      {
   sorter.bubbleSort(S);
      }
    }


    public void keyReleased(KeyEvent ke) { 
    }

  }
}
  

Комментарии:

1. Где код? Пожалуйста, поделитесь, чтобы скорее получить помощь?

2. Не блокируйте EDT (поток отправки событий) — графический интерфейс «зависнет», когда это произойдет. Вместо вызова Thread.sleep(n) реализуйте Swing Timer для повторяющихся задач или SwingWorker для длительно выполняющихся задач. Смотрите Параллелизм в Swing для получения более подробной информации.

3. извините, добавлены коды

Ответ №1:

Примечание: Я начал писать это до того, как вопрос был удален

Скорее всего, вы используете какой-то механизм цикла и молитесь, чтобы на каждой итерации пользовательский интерфейс обновлялся. Это неверное предположение. Пользовательский интерфейс не будет обновляться до завершения цикла. То, что вы делаете, мы называем блокировкой потока отправки событий (EDT)

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

Таким образом, ваш таймер таймера может выглядеть примерно так

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

Ваш sortOnlyOneItem метод должен выполнять сортировку только для одного элемента. И установите какой-нибудь флаг, чтобы проверить, выполнена ли сортировка, затем остановите таймер.


Другие примечания:

  • Вы должны вызывать super.paintComponent в paintComponent методе, если вы не собираетесь рисовать фон самостоятельно. Хотя обычно я всегда так делаю.

Вот полный пример. Я рад, что вы разобрались с этим самостоятельно. Я работал над этим примером, прежде чем увидел, что вы его получили.

введите описание изображения здесь

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

Комментарии:

1. Не могли бы вы написать это также для сортировки пузырьками и сортировки вставкой?

2. Использование таймера сработало для моей панели прогресса, когда ничто другое не могло. Вам просто нужно переписать свой код, чтобы выполнять итерации вместо цикла, как он сказал.