如何在使用 Thread.sleep 时更新 UI
How to update UI when using Thread.sleep
当 运行 我的 BubbleSort 方法时,我希望面板更新以准确显示正在发生的事情,但是当使用 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);
}
}
我希望面板在方法为 运行 时更新,但在方法完成之前使用它仍然是空白。
您正在放置 Thread.sleep(500);直接在 UI 线程上。而是为创建新线程
冒泡排序。因此,如果您将睡眠置于 UI 线程以外的线程上,它不会冻结您的 UI.
更改 ActionListner
以便在单独的线程上完成排序:
@Override
public void actionPerformed(ActionEvent arg0)
{
new Thread(()->bubbleSort(array)).start();
}
要使用 Swing 线程更新 UI,请使用: SwingUtilities.invokeLater(()->repaint());
而不是 this.repaint();
你正在做分类和在 EDT 睡觉
@Override
public void actionPerformed(ActionEvent arg0)
{
bubbleSort(array);
}
这就是所谓的"GUI"线程,actionPerformed
就是由它完成的。 EDT 负责 UI 的绘制和响应。你正在扼杀它,因此冻结。使用 SwingWorker
进行计算(和休眠)和 publish
中间结果,以便 GUI 可以反映更改。
当 运行 我的 BubbleSort 方法时,我希望面板更新以准确显示正在发生的事情,但是当使用 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);
}
}
我希望面板在方法为 运行 时更新,但在方法完成之前使用它仍然是空白。
您正在放置 Thread.sleep(500);直接在 UI 线程上。而是为创建新线程 冒泡排序。因此,如果您将睡眠置于 UI 线程以外的线程上,它不会冻结您的 UI.
更改 ActionListner
以便在单独的线程上完成排序:
@Override
public void actionPerformed(ActionEvent arg0)
{
new Thread(()->bubbleSort(array)).start();
}
要使用 Swing 线程更新 UI,请使用: SwingUtilities.invokeLater(()->repaint());
而不是 this.repaint();
你正在做分类和在 EDT 睡觉
@Override
public void actionPerformed(ActionEvent arg0)
{
bubbleSort(array);
}
这就是所谓的"GUI"线程,actionPerformed
就是由它完成的。 EDT 负责 UI 的绘制和响应。你正在扼杀它,因此冻结。使用 SwingWorker
进行计算(和休眠)和 publish
中间结果,以便 GUI 可以反映更改。