Java свинг-визуализация - PullRequest
1 голос
/ 22 марта 2020

Я новичок в java программировании, и я пытаюсь сделать своего рода визуализацию. Как вы можете видеть в верхней части окна (в ссылке) есть JTextArea, здесь я могу поместить свой массив, и нажав Enter, программа создаст матрицу кнопок. Программа нарисует для каждого столбца n кнопок. Так что я могу представить цифры в графическом виде. Когда нажимается пузырьковая сортировка, я хочу увидеть анимацию пузырьковой сортировки, чтобы графически отсортировать массив, но когда я это делаю, setBackground в классе анимации ничего не делает. Я использовал таймер, почему я обнаружил в inte rnet, что свинг не позволяет многократно вызывать перерисовку за короткое время. Ниже я поставил ссылку GUI. Код:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.util.ArrayList;
class animation implements ActionListener{
    private JButton grid[][];
    private int i;
    private int j;
    private int N;
    animation(JButton grid[][], int N, int i, int j){
        this.grid=grid;
        this.N=N;
        this.i=i;
        this.j=j;
    }
    public void actionPerformed(ActionEvent e){
        JButton tmp[]=new JButton[N];
        for(int y=0;y<N;++y){
            tmp[y]=new JButton();
            tmp[y].setBackground(grid[y][i].getBackground());
        }
        for(int y=0;y<N;++y){
            grid[y][i].setBackground(grid[y][j].getBackground());
            grid[y][j].setBackground(tmp[y].getBackground());
        }
        return;
    }
}
class sortInterface extends JFrame implements ActionListener{
    //components declaration
    private ArrayList<Integer> arr=new ArrayList<Integer>();
    private JPanel simulation=new JPanel();
    private JButton grid[][];
    private JPanel algorithm=new JPanel();
    private JPanel frontPanel=new JPanel();
    private JLabel title=new JLabel("SORTING ALGORITHMS", JLabel.CENTER);
    private JTextField input=new JTextField();
    private JButton enter=new JButton("ENTER");
    private JButton bubble=new JButton("Bubble Sort");
    private JButton insertion=new JButton("Insertion Sort");
    private JButton selection=new JButton("Selection Sort");
    private JButton quick=new JButton("Quick Sort");
    private JButton merge=new JButton("Merge Sort");
    //here start the GUI 
    private void setFrame(){
        setLayout(new BorderLayout());
        add(frontPanel, "North");
        add(simulation, "Center");
        add(algorithm, "South");
        setSize(720, 480);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        return;
    }
    private void setFrontPanel(){
        frontPanel.setLayout(new BorderLayout());
        frontPanel.add(title, "North");
        frontPanel.add(input, "Center");
        frontPanel.add(enter, "South");
        return;
    }
    private void setAlgorithm(){
        algorithm.add(bubble);
        algorithm.add(insertion);
        algorithm.add(selection);
        algorithm.add(quick);
        algorithm.add(merge);
        return;
    }
    private void setListeners(){
        enter.addActionListener(new buttonHandler(simulation, arr, input));
        bubble.addActionListener(new buttonHandler(simulation, arr, input));
        return;
    }
    //here start the computational part
    private boolean isNumber(char car){
        if(car=='1'||car=='2'||car=='3'||car=='4'||car=='5'||car=='6'||car=='7'||car=='8'||car=='9'||car=='0')
            return true;
        return false;
    }
    private int convertSubStringToInt(String read, int i){
        String tmp="";
        while(isNumber(read.charAt(i))&&i<read.length()){
            tmp=tmp+String.valueOf(read.charAt(i));  
            ++i;
        }
        return (Integer.parseInt(tmp));
    }   
    private void addElementToArray(String read){
        boolean flag=true;
        for(int i=0;i<read.length();++i){
            if(read.charAt(i)==' ')
                flag=true;
            if(isNumber(read.charAt(i))&&flag){
                arr.add(convertSubStringToInt(read, i));
                flag=false;
            }
        }
        return;
    }
    private int findMax(){
        int maxIndex=0;
        for(int i=1;i<arr.size();++i)
            if(arr.get(maxIndex)<arr.get(i))
                maxIndex=i;
        return arr.get(maxIndex);
    }
    private void setSimulation(){
        int max=findMax();
        int constMax=max;
        grid=new JButton[max][arr.size()];
        simulation.removeAll();
        simulation.revalidate();
        simulation.repaint();
        simulation.setLayout(new GridLayout(max, arr.size()));
        for(int i=0;i<constMax;++i){
            for(int j=0;j<arr.size();++j){
                grid[i][j]=new JButton();
                if(arr.get(j)>=max)
                    grid[i][j].setBackground(Color.white);
                else
                    grid[i][j].setBackground(Color.black);
                simulation.add(grid[i][j]);
            }
            --max;
        }
        simulation.validate();
        return;
    }
    sortInterface(){
        setFrame();
        setFrontPanel();
        setAlgorithm();
        setListeners();
    }
    public void actionPerformed(ActionEvent e){
        String read=e.getActionCommand();
        if(read=="ENTER"){
            arr.clear();
            addElementToArray(input.getText()+" ");
            setSimulation();
        }
        else if(read=="Bubble Sort"){
            for(int i=0;i<arr.size()-1;++i)
                for(int j=0;j<arr.size()-1-i;++j)
                    if(arr.get(j)>arr.get(j+1)){
                        int tmp=arr.get(j);
                        arr.set(j, arr.get(j+1));
                        arr.set(j+1, tmp);
                        Timer time=new Timer(1, new animation(grid, arr.size(), j, j+1));
                        time.start();
                        try{
                            Thread.sleep(200);
                        }
                        catch(Exception sleep){
                            //prova
                        }
                        time.stop();
                    }
        }
        else if(read=="Insertion Sort"){

        }
        else if(read=="Selection Sort"){

        }
        else if(read=="Quick Sort"){

        }
        else{

        }
        return;
    }
}
class projSortInterface
{
    public static void main(String argv[])
    {
        sortInterface prova=new sortInterface();
        prova.setVisible(true);
        return; 
    }
}

GUI

Ответы [ 2 ]

1 голос
/ 22 марта 2020

Как сказал Джони, вы не должны спать в ActionListener, потому что каждый ActionListener вызывается в потоке диспетчеризации событий. Любая существенная задержка помешает Swing нарисовать любые ваши изменения (и также не даст Swing отреагировать на любой ввод пользователя).

Но вы можете выполнить вашу логику c и ваши сны в другой ветке. Единственное, что вам нужно помнить, это то, что вызовы методов Swing и конструкторов Swing могут не выполняться в другом потоке; при работе в другом потоке вы должны использовать EventQueue.invokeLater для выполнения этих вызовов методов.

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

Runnable sortTask = () -> {
    try {
        for (int i=0; i < arr.size()-1; ++i) {
            for (int j=0; j < arr.size()-1-i; ++j) {
                if (arr.get(j) > arr.get(j+1)) {
                    int tmp = arr.get(j);
                    arr.set(j, arr.get(j+1));
                    arr.set(j+1, tmp);

                    int index1 = j;
                    int index2 = j+1;

                    EventQueue.invokeLater(() -> {
                        animation a =
                            new animation(grid, arr.size(), index1, index2);
                        a.actionPerformed(null);
                    });

                    Thread.sleep(200);
                }
            }
        }
    } catch (InterruptedException e) {
        System.out.println("Interrupted.  Terminating sort.");
    }
};

new Thread(sortTask, "Sort").start();

Как видите, вся операция сортировки была перемещена в Runnable, который затем передается в новый поток. Фактическая «анимация» выполняется в отдельном небольшом Runnable, который передается в EventQueue.invokeLater, поскольку он содержит операции Swing и не разрешен для запуска в любом потоке, кроме потока диспетчеризации событий.

Возможно для выполнения sh вашего рода с использованием таймера, но для этого потребуется перестройка вашей логики c. Вы не сможете использовать петли for. Я думаю, что создание Thread и сохранение использования for будет более читабельным и с ним легче работать.

Некоторые другие примечания:

  • Обратите внимание, что try / улов вокруг всего вида. Прерывания не случаются случайно; если кто-то прерывает ваш поток, это означает, что он просит вас прекратить то, что вы делаете и выйти как можно более чисто. Позволяя InterruptedException выходить из l oop, когда программа перемещает выполнение в блок catch, вы выполняете этот запрос.
  • Никогда не перехватывает Exception. Существует множество непроверенных исключений, которые существуют для выявления ошибок программиста, таких как NullPointerException, IllegalArgumentException и IndexOutOfBoundsException. Вы хотите, чтобы остановили вашу программу, потому что они содержат ошибки, которые вы, программист, должны исправить. Их подавление не заставит программу работать.
  • Как отметил Джордж З., строки - это объекты, и вы никогда не должны сравнивать объекты, используя ==, так как это не проверяет, равны ли они по значению. , он сравнивает, являются ли они одним и тем же объектом, созданным в одном и том же месте в программе. Как сравнить строки в Java? объясняет это подробно. (Есть несколько особых случаев, когда безопасно сравнивать объекты с ==, но строки определенно не входят в их число.)
  • Переменные index1 и index2 необходимы, потому что могут быть только конечные переменные перешел во внутренние классы и лямбды. Они не должны быть объявлены с final (хотя это разрешено); они просто должны быть эффективно окончательными, такими, какие они есть, потому что им присваивается значение только один раз.
1 голос
/ 22 марта 2020

Вы вызываете Thread.sleep (200) в обработчике событий - не надо.

Swing является однопоточным. Он имеет один единственный поток (называемый потоком отправки событий, EDT), который делает все: рисует, обрабатывает события и т. Д. c. Если вы заставляете эту нить спать, она не может делать ничего другого, например рисовать или реагировать на щелчки.

...