简体   繁体   English

Java Swing排序可视化

[英]Java swing sort visualization

i'm new in java programming and i'm trying to make a sort visualization.我是 Java 编程新手,正在尝试进行排序可视化。
How you can see top the window (in the link) there is a JTextArea, here i can put my array and pressing enter the programm will build a matrix of buttons.您如何看到窗口顶部(在链接中)有一个 JTextArea,在这里我可以放置我的数组并按 Enter 程序将构建一个按钮矩阵。 The program will paint for every columns n buttons.该程序将为每列 n 个按钮绘制。 So i can represent the numbers graphically.所以我可以用图形表示数字。 When bubble sort is pressed, i want to make see the animation of the bubble sort to sort the array graphically but when i do that, setBackground in animation class doesn't do anything.当按下冒泡排序时,我想查看冒泡排序的动画以图形方式对数组进行排序,但是当我这样做时,动画类中的 setBackground 不做任何事情。
I used a timer why i found in internet that swing doesn't allow to call repaint multiple times in short time.我使用了一个计时器,为什么我在互联网上发现 Swing 不允许在短时间内多次调用重绘。
Below i put a link of the GUI.下面我放了一个GUI的链接。
Code:代码:

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图形用户界面

You're calling Thread.sleep(200) within an event handler - don't.您正在事件处理程序中调用 Thread.sleep(200) - 不要。

Swing is single threaded. Swing 是单线程的。 It has one single thread (called event dispatch thread, EDT) that does everything: paints, handles events, etc. If you're making that thread sleep, it can't do anything else like paint or respond to clicks.它有一个单独的线程(称为事件调度线程,EDT)可以完成所有事情:绘制、处理事件等。如果您让该线程休眠,它就不能做任何其他事情,例如绘制或响应点击。

As Joni said, you must not sleep in an ActionListener, because every ActionListener is called in the Event Dispatch Thread.正如 Joni 所说,你不能在 ActionListener 中睡觉,因为每个 ActionListener 都是在 Event Dispatch Thread 中调用的。 Any significant delay will prevent Swing from painting any of your changes (and will also prevent Swing from responding to any user input).任何显着的延迟都会阻止 Swing 绘制您的任何更改(并且还会阻止 Swing 响应任何用户输入)。

But you can perform your logic and your sleeps in a different thread.但是您可以不同的线程中执行您的逻辑和睡眠。 The only thing you need to remember is that calls to Swing methods and Swing constructors may not be performed in a different thread;您唯一需要记住的是,对 Swing 方法和 Swing 构造函数的调用可能不会在不同的线程中执行; while running in a different thread, you must use EventQueue.invokeLater to execute those method calls.在不同线程中运行时,您必须使用EventQueue.invokeLater来执行这些方法调用。

Using a new thread, it would look something like this:使用一个新线程,它看起来像这样:

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

As you can see, the entire sort operation has been moved into a Runnable, which is then passed to a new Thread.如您所见,整个排序操作已移动到一个 Runnable 中,然后将其传递给一个新的 Thread。 The actual 'animation' is done in a separate small Runnable which is passed to EventQueue.invokeLater , since it contains Swing operations and is not permitted to run in any thread other than the Event Dispatch Thread.实际的“动画”在传递给EventQueue.invokeLater的单独的小 Runnable 中完成,因为它包含 Swing 操作并且不允许在除事件调度线程之外的任何线程中运行。

It is possible to accomplish your sort using a Timer, but it would require rearranging your logic.可以使用 Timer 完成排序,但这需要重新安排您的逻辑。 You would not be able to use for loops.您将无法使用for循环。 I think creating a Thread and retaining the use of for will be more readable and easier to work with in this case.我认为在这种情况下创建一个线程并保留for的使用将更具可读性和更容易使用。

Some other notes:其他一些注意事项:

  • Notice that the try/catch is around the entire sort.请注意,try/catch 是围绕整个排序的。 Interrupts do not happen by accident;中断不是偶然发生的; if someone interrupts your thread, it means they are asking you to stop what you're doing and exit as cleanly as possible.如果有人打断了您的线程,则意味着他们要求您停止正在执行的操作并尽可能干净地退出。 By allowing an InterruptedException to exit the loop when the program moves execution to the catch block, you are honoring this request.当程序将执行移动到catch块时,通过允许 InterruptedException 退出循环,您就是在尊重这个请求。
  • Never catch Exception .永远不要捕获Exception There are a lot of unchecked exceptions which exist to expose programmer errors, like NullPointerException, IllegalArgumentException, and IndexOutOfBoundsException.有很多未经检查的异常会暴露程序员的错误,比如 NullPointerException、IllegalArgumentException 和 IndexOutOfBoundsException。 You want those to terminate your program, because they expose errors that you, the programmer, need to fix.希望它们终止您的程序,因为它们会暴露您作为程序员需要修复的错误。 Suppressing them will not make the program work.抑制它们不会使程序运行。
  • As George Z. pointed out, Strings are objects, and you should never compare objects using == , since that doesn't check whether they're equal in value, it compares whether they are the same object created in the same place in the program.正如 George Z. 指出的,字符串是对象,你永远不应该使用==比较对象,因为这不会检查它们的值是否相等,它比较它们是否是在相同位置创建的相同对象程序。 How do I compare strings in Java? 我如何比较Java中的字符串? explains this in detail.详细解释了这一点。 (There are a few special cases where it's safe to compare objects with == , but Strings definitely are not among them.) (在一些特殊情况下,将对象与==进行比较是安全的,但字符串绝对不在其中。)
  • The index1 and index2 variables are needed because only final variables can be passed to inner classes and lambdas.需要index1index2变量,因为只有 final 变量可以传递给内部类和 lambdas。 They don't need to be declared with final (though it is allowed);它们不需要用final声明(尽管它是允许的); they just need to be effectively final, which they are, because they are only assigned a value once.它们只需要有效地最终确定,因为它们只被分配了一次值。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM