【问题标题】:Java swing sort visualizationJava摇摆排序可视化
【发布时间】:2020-07-03 02:53:26
【问题描述】:

我是 Java 编程新手,我正在尝试进行排序可视化。
您如何看到窗口顶部(在链接中)有一个 JTextArea,在这里我可以放置我的数组,然后按 Enter 程序将构建一个按钮矩阵。该程序将为每列绘制 n 个按钮。所以我可以用图形表示数字。当按下冒泡排序时,我想看到冒泡排序的动画以图形方式对数组进行排序,但是当我这样做时,动画类中的 setBackground 不会做任何事情。
我使用了一个计时器,为什么我在互联网上发现 swing 不允许在短时间内多次调用 repaint。
下面我放了一个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

【问题讨论】:

  • read=="Insertion Sort" 这不是您在 Java 中比较字符串的方式。 Read this.
  • 另外,if(car=='1'||car=='2'||car=='3'||car=='4'||car=='5'||car=='6'||car=='7'||car=='8'||car=='9'||car=='0') 似乎不是“编程”。将其替换为Characters#isDigit
  • 我使用了计时器 - 你错过了使用计时器的意义。 Timer 取代了你所有的循环逻辑。因此,如果您单击的按钮是“冒泡排序”,那么您将启动 Timer 并摆脱 Thread.sleep。然后需要更改您的逻辑以跟踪排序的当前状态。每次 Timer 触发时,您都会增加“j”值并进行处理。当“j”达到最大值时,增加“I”值并重置“j”值。如果您希望 GUI 更新每个步骤,则不能有任何循环。

标签: java swing refresh


【解决方案1】:

您在事件处理程序中调用 Thread.sleep(200) - 不要。

Swing 是单线程的。它有一个单独的线程(称为事件调度线程,EDT),可以完成所有工作:绘制、处理事件等。如果你让那个线程休眠,它就不能做任何其他事情,比如绘制或响应点击。

【讨论】:

    【解决方案2】:

    正如 Joni 所说,你不能在 ActionListener 中休眠,因为每个 ActionListener 都在 Event Dispatch Thread 中被调用。任何明显的延迟都会阻止 Swing 绘制您的任何更改(并且还会阻止 Swing 响应任何用户输入)。

    但是你可以在一个不同的线程中执行你的逻辑和你的睡眠。唯一需要记住的是,对 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 中,然后将其传递给新的 Thread。实际的“动画”在传递给EventQueue.invokeLater 的单独的小型 Runnable 中完成,因为它包含 Swing 操作,并且不允许在 Event Dispatch Thread 以外的任何线程中运行。

    可以使用 Timer 完成排序,但需要重新安排逻辑。您将无法使用for 循环。我认为在这种情况下,创建一个线程并保留for 的使用会更具可读性和更易于使用。

    其他一些注意事项:

    • 请注意,try/catch 围绕整个排序。中断不是偶然发生的;如果有人打断了你的线程,这意味着他们要求你停止你正在做的事情并尽可能干净地退出。通过在程序将执行移至 catch 块时允许 InterruptedException 退出循环,您将尊重此请求。
    • 永远不要抓到Exception。存在许多暴露程序员错误的未经检查的异常,例如 NullPointerException、IllegalArgumentException 和 IndexOutOfBoundsException。您希望那些终止您的程序,因为它们暴露了您(程序员)需要修复的错误。抑制它们不会使程序运行。
    • 正如 George Z. 所指出的,字符串是对象,您永远不应该使用 == 比较对象,因为这不会检查它们的值是否相等,它会比较它们是否是在程序中的同一个地方。 How do I compare strings in Java? 详细解释了这一点。 (有一些特殊情况可以安全地将对象与== 进行比较,但字符串绝对不在其中。)
    • 需要index1index2 变量,因为只有最终变量可以传递给内部类和lambda。它们不需要用final 声明(尽管允许);它们只需要实际上是最终的,它们就是这样,因为它们只被赋值一次。

    【讨论】:

    • 我尝试将此代码放在 else if(read.equals("Bubble Sort")) 之后,但它不起作用。我该怎么办?
    • “它不起作用”是什么意思?你怎么知道它不起作用?
    • 最后一个问题,使用swing worker而不是创建两个线程不是更好吗?
    • 你可以使用 SwingWorker,但不会更好。它会做同样的事情:创建另一个调用 doInBackground 的线程。您将不得不重复发布整个 ArrayList,因此这将是相同的逻辑,但代码行数会稍多一些。
    猜你喜欢
    • 2010-12-16
    • 1970-01-01
    • 2013-06-27
    • 1970-01-01
    • 1970-01-01
    • 2012-11-20
    • 2014-04-19
    • 1970-01-01
    • 2013-07-02
    相关资源
    最近更新 更多