我打印简单的值来JTextArea
使用简单的for循环追加,当我运行它时,如果我在控制台输出中打印值,它就正常运行...
但是如果我JTextArea
在文本区域中追加并打印值,则在整个程序运行后将它们全部附加.
public class SwingThread { private JFrame frame; /** * Launch the application. */ public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { SwingThread window = new SwingThread(); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } /** * Create the application. */ public SwingThread() { initialize(); } /** * Initialize the contents of the frame. */ private void initialize() { frame = new JFrame(); frame.setBounds(100, 100, 450, 300); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JScrollPane scrollPane = new JScrollPane(); frame.getContentPane().add(scrollPane, BorderLayout.CENTER); JTextArea textArea = new JTextArea(); scrollPane.setViewportView(textArea); JButton btnNewButton = new JButton("New button"); scrollPane.setColumnHeaderView(btnNewButton); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { try { for(int i = 0 ; i <= 5 ; i++) { textArea.append("Value "+i+"\n"); System.out.println("Value is" + i); Thread.sleep(1000); } } catch(Exception e) { System.out.println("Error : "+e); } } }); } }
我想逐个追加,但是在整个程序运行后附加了它.
您的问题在于使用Thread.sleep
,因为当您在Swing事件线程(或事件调度线程的EDT)上调用它时,它将使整个Swing事件线程进入休眠状态.当发生这种情况时,无法执行此线程的操作,包括绘制GUI(更新它)以及与用户交互,这将完全冻结您的GUI - 不好.在当前情况下的解决方案是使用Swing Timer作为伪循环.Timer在后台线程中创建一个循环,并保证其actionPerformed方法中的所有代码都将在Swing事件线程上调用,这是必需的,因为我们不希望从该线程附加到JTextArea.
还有其他人注意到,如果你想要做的就是在Swing中执行延迟重复动作,那么是的,使用这个Swing Timer.另一方面,如果您希望在Swing中运行长时间运行的代码,则此代码将再次阻止EDT并冻结您的程序.对于这种情况,请使用后台线程,例如SwingWorker提供的后台线程.有关详细信息,请查看课程:Swing中的并发.
例如,
btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { // delay between timer ticks: 1000 int timerDelay = 1000; new Timer(timerDelay, new ActionListener() { private int counter = 0; @Override public void actionPerformed(ActionEvent e) { // timer's stopping condition if (counter >= MAX_VALUE) { // MAX_VALUE is a constant int = 5 ((Timer) e.getSource()).stop(); } else { textArea.append("Value " + counter + "\n"); } counter++; // increment timer's counter variable } }).start(); } });
整个东西:
import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.event.*; import javax.swing.*; public class SwingThread2 { protected static final int MAX_VALUE = 5; // our constant private JFrame frame; public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { SwingThread2 window = new SwingThread2(); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } public SwingThread2() { initialize(); } private void initialize() { frame = new JFrame(); // frame.setBounds(100, 100, 450, 300); // avoid this frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JScrollPane scrollPane = new JScrollPane(); frame.getContentPane().add(scrollPane, BorderLayout.CENTER); JTextArea textArea = new JTextArea(15, 40); scrollPane.setViewportView(textArea); JButton btnNewButton = new JButton("New button"); scrollPane.setColumnHeaderView(btnNewButton); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { // delay between timer ticks: 1000 int timerDelay = 1000; new Timer(timerDelay, new ActionListener() { private int counter = 0; @Override public void actionPerformed(ActionEvent e) { // timer's stopping condition if (counter >= MAX_VALUE) { // MAX_VALUE is a constant int = 5 ((Timer) e.getSource()).stop(); } else { textArea.append("Value " + counter + "\n"); } counter++; // increment timer's counter variable } }).start(); } }); // better to avoid setting sizes but instead to // let the components size themselves vis pack frame.pack(); frame.setLocationRelativeTo(null); } }
仅供参考,以下是上述相同程序的示例,该程序使用SwingWorker执行长时间运行操作,然后使用此操作更新JProgressBar.工作者非常简单,只需使用while循环就可以通过有限的随机数推进计数器变量.然后它传输使用这个值来更新它自己的progress属性(一个只能从0到100的值,因此在其他情况下,需要对该值进行规范化以符合这一点).我将一个PropertyChangeListener附加到worker,并且每当工作程序的进度值发生更改时以及SwingWorker更改状态时(例如操作完成时)都会在Swing事件线程上通知.在后一种情况下,worker的StateValue变为StateValue.DONE.然后,侦听器相应地更新GUI.请问是否有任何问题.
import java.awt.BorderLayout; import java.awt.EventQueue; import java.awt.event.*; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; import java.util.Random; import java.util.concurrent.ExecutionException; import javax.swing.*; public class SwingThread2 { protected static final int MAX_VALUE = 5; // our constant private JFrame frame; private JProgressBar progressBar = new JProgressBar(); public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { try { SwingThread2 window = new SwingThread2(); window.frame.setVisible(true); } catch (Exception e) { e.printStackTrace(); } } }); } public SwingThread2() { initialize(); } private void initialize() { frame = new JFrame(); // frame.setBounds(100, 100, 450, 300); // avoid this frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JScrollPane scrollPane = new JScrollPane(); frame.getContentPane().add(scrollPane, BorderLayout.CENTER); JTextArea textArea = new JTextArea(15, 40); scrollPane.setViewportView(textArea); JButton btnNewButton = new JButton("New button"); scrollPane.setColumnHeaderView(btnNewButton); btnNewButton.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent arg0) { // delay between timer ticks: 1000 int timerDelay = 1000; new Timer(timerDelay, new ActionListener() { private int counter = 0; @Override public void actionPerformed(ActionEvent e) { // timer's stopping condition if (counter >= MAX_VALUE) { // MAX_VALUE is a constant // int = 5 ((Timer) e.getSource()).stop(); } else { textArea.append("Value " + counter + "\n"); } counter++; // increment timer's counter variable } }).start(); } }); progressBar.setStringPainted(true); JPanel bottomPanel = new JPanel(); bottomPanel.setLayout(new BoxLayout(bottomPanel, BoxLayout.LINE_AXIS)); bottomPanel.add(new JButton(new MyAction("Press Me"))); bottomPanel.add(progressBar); frame.getContentPane().add(bottomPanel, BorderLayout.PAGE_END); // better to avoid setting sizes but instead to // let the components size themselves vis pack frame.pack(); frame.setLocationRelativeTo(null); } private class MyAction extends AbstractAction { public MyAction(String name) { super(name); int mnemOnic= (int) name.charAt(0); putValue(MNEMONIC_KEY, mnemonic); } public void actionPerformed(ActionEvent e) { progressBar.setValue(0); setEnabled(false); MyWorker myWorker = new MyWorker(); myWorker.addPropertyChangeListener(new WorkerListener(this)); myWorker.execute(); } } private class WorkerListener implements PropertyChangeListener { private Action action; public WorkerListener(Action myAction) { this.action = myAction; } @Override public void propertyChange(PropertyChangeEvent evt) { if ("progress".equals(evt.getPropertyName())) { int progress = (int) evt.getNewValue(); progressBar.setValue(progress); } else if ("state".equals(evt.getPropertyName())) { if (evt.getNewValue() == SwingWorker.StateValue.DONE) { action.setEnabled(true); @SuppressWarnings("rawtypes") SwingWorker worker = (SwingWorker) evt.getSource(); try { // always want to call get to trap and act on // any exceptions that the worker might cause // do this even though get returns nothing worker.get(); } catch (InterruptedException | ExecutionException e) { e.printStackTrace(); } } } } } private class MyWorker extends SwingWorker{ private static final int MULTIPLIER = 80; private int counter = 0; private Random random = new Random(); @Override protected Void doInBackground() throws Exception { while (counter <100) { int increment = random.nextInt(10); Thread.sleep(increment * MULTIPLIER); counter += increment; counter = Math.min(counter, 100); setProgress(counter); } return null; } } }