如何在使用Thread.sleep时更新UI

问题描述 投票:0回答:3

运行我的冒泡排序方法时,我想要一个面板更新,准确显示正在发生的事情,但是在使用Thread.sleep时,面板会冻结,直到方法完成。

我听说过使用Swing计时器,我知道如何使用它们,但不知道如何实现它们'mid-method'来暂停和继续。

import java.awt.Color;
import java.awt.Font;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Arrays;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextArea;
import javax.swing.SwingConstants;

@SuppressWarnings("serial")
public class BubbleSort extends JPanel implements ActionListener
{  
    int swaps;
    int maxswaps;
    int[] array;
    JLabel arrayLabel;
    JLabel tipLabel = new JLabel();;

    private void bubbleSort(int[] array)
    {  
        maxswaps = (int) Math.pow(array.length,2);
        int tempnum = 0;  
        for(int i=0; i < array.length; i++)
        {  
            for(int num=1; num < (array.length-i); num++)
            {  
                if(array[num-1] > array[num])
                {  
                    tempnum = array[num-1];  
                    array[num-1] = array[num];  
                    array[num] = tempnum;  
                    tipLabel.setText("Swapping " + tempnum + " and " + array[num-1]);
                    arrayLabel.setText(Arrays.toString(array));
                    this.repaint();
                    swaps++;
                    try
                    {
                        Thread.sleep(500);
                        // this is where I want it to sleep         
                    }
                    catch (InterruptedException e)
                    {

                    }

                } 
            }  
        }  
    }  



    public static void moveToMiddle(JFrame frame)
    {
        GraphicsDevice gd = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
        int screenWidth = gd.getDisplayMode().getWidth();
        int screenHeight = gd.getDisplayMode().getHeight();
        frame.setBounds((screenWidth/2) - (frame.getWidth()/2), (screenHeight/2) - (frame.getHeight()/2), frame.getWidth(), frame.getHeight());
    }

    public static void main(String[] args)
    {  
        JPanel panel = new BubbleSort();
        panel.setLayout(null);
        panel.setBackground(Color.WHITE);
        panel.setFocusable(true);

        JFrame frame = new JFrame("Bubble Sort");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);        
        frame.setSize(800, 500);
        frame.setContentPane(panel);
        frame.setVisible(true);
        moveToMiddle(frame);
    }  

    public BubbleSort()
    {
        int arrayLength = 12;
        int maxNumber = 100;
        int minNumber = 0;

        array = new int[arrayLength]; 
        Random r = new Random();
        for(int i=0; i < array.length; i++)
        {
            int num = r.nextInt(maxNumber) + minNumber;
            array[i] = num;
        }

        arrayLabel = new JLabel(Arrays.toString(array));
        arrayLabel.setFont(new Font("Bahnschrift", Font.PLAIN, 35));
        arrayLabel.setBounds(100, 100, 600, 100);

        tipLabel.setBounds(100 , 250 , 600, 100);
        tipLabel.setFont(new Font("Bahnschrift", Font.PLAIN, 35));

        tipLabel.setVerticalAlignment(SwingConstants.CENTER);
        tipLabel.setHorizontalAlignment(SwingConstants.CENTER);

        arrayLabel.setVerticalAlignment(SwingConstants.CENTER);
        arrayLabel.setHorizontalAlignment(SwingConstants.CENTER);

        JButton startButton = new JButton("Start");
        startButton.addActionListener(this);
        startButton.setBounds(0,0,50,50);

        this.add(arrayLabel);   this.add(tipLabel); this.add(startButton);
    }

    @Override
    public void actionPerformed(ActionEvent arg0)
    {
        bubbleSort(array);
    }
}  

我希望在方法运行时更新面板,但在方法完成之前使用它仍然是空白的。

java swing event-dispatch-thread
3个回答
1
投票

更改ActionListner,以便在单独的线程中完成排序:

@Override
public void actionPerformed(ActionEvent arg0)
{
    new Thread(()->bubbleSort(array)).start();
}

要使用Swing线程更新UI,请使用:SwingUtilities.invokeLater(()->repaint());而不是this.repaint();


1
投票

你正在放置Thread.sleep(500);直接在UI线程上。而是为冒泡排序创建新线程。因此,如果您将睡眠放在UI线程以外的线程上,它将不会冻结您的UI。


0
投票

您正在EDT中进行排序和休眠

   @Override
    public void actionPerformed(ActionEvent arg0)
    {
        bubbleSort(array);
    }

这就是所谓的“GUI”线程,actionPerformed由它完成。 EDT负责UI的绘制和响应。你正在塞它,因此冻结。使用SwingWorker进行计算(和休眠)和publish中间结果,以便GUI可以反映更改。

© www.soinside.com 2019 - 2024. All rights reserved.