更新 JFrame 并使用 Thread.sleep() [重复]
Posted
技术标签:
【中文标题】更新 JFrame 并使用 Thread.sleep() [重复]【英文标题】:Updating JFrame and using Thread.sleep() [duplicate] 【发布时间】:2014-04-29 12:55:05 【问题描述】:我一直在努力解决一个我现在不太了解的奇怪问题(我对线程的了解很少):
我有一个 JFrame 类,它应该使用 JButtons 来代表队列中的客户。有一个名为simulate() 的方法,本质上,每次调用它时都会向JFrame 添加一个新的JButton。我想在每次调用后重复调用该方法并短暂暂停。为此,我尝试了以下方法:
private void goButtonActionPerformed(java.awt.event.ActionEvent evt)
try
for(int i = 0; i < sim.length ; i++)
simulate();
Thread.sleep(500);
catch (Exception e)
但程序只是等到循环完成更新 JFrame(即,几秒钟后突然出现五个客户,而不是每半秒到达一个)。有什么问题?我是否导致错误的线程进入睡眠状态?我可以使用 wait() 吗?
完整的程序真的很长,但如果有帮助,我会在此处包含它:
package homeworkfour;
import java.awt.Color;
import java.awt.Component;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import javax.swing.JTextField;
public class GUI extends javax.swing.JFrame
final private int w = 60, h = 20;
ArrayList<Integer> busy = new ArrayList<>();
ArrayList<Integer> linePositions;
ArrayList<Integer> kioskPositions;
public Simulator sim = new Simulator();
private boolean fastMode = false;
public GUI()
initComponents();
busy.add(-1);//BEFORE -1 IS BROKEN KIOSKS, AFTER IS FIXERS
this.getContentPane().setBackground(new Color(255,240,240));//reddish background? maybe
this.setVisible(false);
private void simulate(boolean fastMode) throws InterruptedException
ArrayList<Integer> feedback;
int spaces = (int)((double)(375 - (sim.num_cashiers * w))/(double)sim.num_cashiers);
int kspaces = (int)((double)(375 - (sim.num_kiosks * w))/(double)sim.num_kiosks);
feedback = sim.simulate();
if(feedback.get(0)!=0)//a customer spawned, add a button!!
JButton cButton = buildButton();
System.out.println(feedback.get(0));
boolean kiosk = feedback.get(0) < 0;//these
feedback.set(0, Math.abs(feedback.get(0)));//lines
int lineNumber = feedback.get(0)%100;//parse
int waitTime = feedback.get(0)/100;//feedback[0]
cButton.setText(String.valueOf(waitTime));
cButton.setVisible(true);
//System.out.println("cSpawn~");
if(!kiosk)
cButton.setBounds((spaces/2)+(lineNumber*(spaces+w)), linePositions.get(lineNumber), w, h);
linePositions.set(lineNumber, linePositions.get(lineNumber)+35);
else//they joined a kiosk
cButton.setBounds(375 + (kspaces/2)+(lineNumber*(kspaces+w)),kioskPositions.get(lineNumber),w,h);
kioskPositions.set(lineNumber,kioskPositions.get(lineNumber)+35);
this.add(cButton);
//System.out.println(cButton.getBounds().getLocation().toString());
if(feedback.get(1)!=0)//hey someone finished this turn!
sim.totalTimeWaited+=feedback.get(1);
//we will remove their button in another block(:
for (int i = 2,value = feedback.get(i); value != -1; i++, value = feedback.get(i)) //goes through all cashiers who lose a customer
remove(getComponentAt((spaces/2)+(value*(spaces+w)), 65));
reButton(i);
for (int i = feedback.indexOf(-1)+1, value = feedback.get(i); value!= -2; i++,value = feedback.get(i))//kiosks...
remove(getComponentAt(375 + (kspaces/2)+(value*(kspaces+w)),65));
reButton(-i);
for (int i = feedback.indexOf(-2)+1, value = feedback.get(i); value!=-3;i++,value = feedback.get(i))//goes through broken kiosks
busy.add(0,value);
getComponentAt(375+(kspaces/2)+(value*kspaces+w), 30).setBackground(Color.red);
for (int i = feedback.indexOf(-3)+1, value = feedback.get(i); value!=-4;i++,value = feedback.get(i))//goes through fixer dudes
busy.add(busy.indexOf(-1)+1,value);
getComponentAt((spaces/2)+(value*spaces+w), 30).setBackground(Color.red);
for (int i = 0; i < sim.num_cashiers; i++)
if(sim.cashiers[i].getRepairTime()==0)
getComponentAt((spaces/2)+(i*spaces+w), 30).setBackground(Color.black);
for (int i = 0; i < sim.num_kiosks; i++)
if(!sim.kiosks[i].broken)
getComponentAt((kspaces/2)+(i*kspaces+w), 30).setBackground(Color.black);
jLabel1.setText("Time = "+sim.time);
jLabel3.setText("Orders = "+sim.orders);
revalidate();
repaint();
Thread.sleep(300);
private void reButton(int line)
int y = 65;
int x;
Component c;
int spaces = (int)((double)(375 - (sim.num_cashiers * w))/(double)sim.num_cashiers);
int kspaces = (int)((double)(375 - (sim.num_kiosks * w))/(double)sim.num_kiosks);
if(line>0)//ITS A CASHIER LINE
x = ((spaces/2)+(line*(spaces+w)));
for(;getComponentAt(x,y)!=null;y+=35)
getComponentAt(x,y).setLocation(x, y-35);
else//ITS A KIOSK LINE
x = (375 + (kspaces/2)+(-line*(kspaces+w)));
for(;getComponentAt(x,y)!=null;y+=35)
getComponentAt(x,y).setLocation(x, y-35);
revalidate();
repaint();
private JButton buildButton()
JButton button = new JButton();
button.setContentAreaFilled(false);
button.setOpaque(true);
button.setBorderPainted(false);
button.setForeground(Color.black);
button.setBackground(Color.white);
button.setVisible(true);
return button;
public void buildLines()
JButton temp;
linePositions = new ArrayList<>(sim.num_cashiers);
kioskPositions = new ArrayList<>(sim.num_kiosks);
for (int i = 0; i < sim.num_cashiers; i++)
linePositions.add(65);
for (int i = 0; i < sim.num_kiosks; i++)
kioskPositions.add(65);
//System.out.println(linePositions.size());
for (int i = 0; i < sim.num_cashiers; i++) //sets up cashier buttons
temp = buildButton();
int spaces = (int)((double)(375 - (sim.num_cashiers * w))/(double)sim.num_cashiers);
temp.setBounds((spaces/2)+(i*(spaces+w)),30,w,h);
temp.setText("~C~");
temp.setBackground(Color.darkGray);
temp.setForeground(Color.white);
this.add(temp);
for (int i = 0; i < sim.num_kiosks; i++) //sets up cashier buttons
temp = buildButton();
int spaces = (int)((double)(375 - (sim.num_kiosks * w))/(double)sim.num_kiosks);
temp.setBounds((375+(spaces/2))+(i*(spaces+w)),30,w,h);
temp.setText("~K~");
temp.setBackground(Color.darkGray);
temp.setForeground(Color.white);
this.add(temp);
/**
* This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always
* regenerated by the Form Editor.
*/
@SuppressWarnings("unchecked")
// <editor-fold defaultstate="collapsed" desc="Generated Code">
private void initComponents()
jPanel1 = new javax.swing.JPanel();
fastModeButton = new javax.swing.JToggleButton();
jButton1 = new javax.swing.JButton();
jLabel1 = new javax.swing.JLabel();
jLabel3 = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
setTitle("CSE214HW4");
setBackground(new java.awt.Color(255, 230, 230));
setPreferredSize(new java.awt.Dimension(750, 435));
jPanel1.setBackground(new java.awt.Color(230, 230, 255));
jPanel1.setMinimumSize(new java.awt.Dimension(100, 30));
fastModeButton.setText("Toggle Fast Mode");
fastModeButton.setMaximumSize(new java.awt.Dimension(140, 20));
fastModeButton.setMinimumSize(new java.awt.Dimension(140, 20));
fastModeButton.addActionListener(new java.awt.event.ActionListener()
public void actionPerformed(java.awt.event.ActionEvent evt)
fastModeButtonActionPerformed(evt);
);
jButton1.setText("Simulate");
jButton1.addActionListener(new java.awt.event.ActionListener()
public void actionPerformed(java.awt.event.ActionEvent evt)
jButton1ActionPerformed(evt);
);
jLabel1.setFont(new java.awt.Font("Lucida Console", 0, 20)); // NOI18N
jLabel1.setText("Time = 0");
jLabel3.setFont(new java.awt.Font("Lucida Console", 0, 20)); // NOI18N
jLabel3.setText("Orders = 0");
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 13, Short.MAX_VALUE)
.addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(206, 206, 206)
.addComponent(fastModeButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jButton1)
.addContainerGap())
);
jPanel1Layout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(fastModeButton, javax.swing.GroupLayout.DEFAULT_SIZE, 22, Short.MAX_VALUE)
.addComponent(jButton1, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(jLabel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
.addContainerGap())
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addContainerGap(401, Short.MAX_VALUE)
.addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
);
pack();
// </editor-fold>
private void jButton1ActionPerformed(java.awt.event.ActionEvent evt)
try
//buildLines();
sim.build();
for(int i = 0; i<sim.length;i++)
simulate(fastMode);
Thread.sleep(200);
catch (InterruptedException ex)
Logger.getLogger(GUI.class.getName()).log(Level.SEVERE, null, ex);
private void fastModeButtonActionPerformed(java.awt.event.ActionEvent evt)
fastMode = !fastMode;
/**
* @param args the command line arguments
*/
public static void main(String args[])
/* Set the Nimbus look and feel */
//<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
/* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
* For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html
*/
try
for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
if ("Nimbus".equals(info.getName()))
javax.swing.UIManager.setLookAndFeel(info.getClassName());
break;
catch (ClassNotFoundException ex)
java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
catch (InstantiationException ex)
java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
catch (IllegalAccessException ex)
java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
catch (javax.swing.UnsupportedLookAndFeelException ex)
java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
//</editor-fold>
/* Create and display the form */
java.awt.EventQueue.invokeLater(new Runnable()
public void run()
new GUI().setVisible(true);
);
// Variables declaration - do not modify
private javax.swing.JToggleButton fastModeButton;
private javax.swing.JButton jButton1;
private javax.swing.JLabel jLabel1;
private javax.swing.JLabel jLabel3;
private javax.swing.JPanel jPanel1;
// End of variables declaration
【问题讨论】:
我看过了,但他的情况完全不同,以至于我真的不明白如何实施提供给他的解决方案——他只想要 1 次暂停,并且它附加到 ActionListener。 核心问题是一样的,你正在让负责重新绘制 GUI 的线程进入睡眠状态,所以它永远没有时间实际完成工作。您必须使用不涉及休眠主线程的方法来调用simulate
。
【参考方案1】:
ActionListener 中的代码在 Event Dispatch THread 上执行。 Thread.sleep(...) 导致 EDT 进入睡眠状态,因此 GUI 无法重新绘制自身,直到整个循环执行完毕。
阅读 Concurrency 上的 Swing 教程部分了解更多信息。
如教程中所述,一个解决方案是使用SwingWorker
,然后根据需要“发布”结果。
另一种方法是使用 Swing Timer
来安排更新。该教程还有一个关于How to Use Swing Timers
的部分。
【讨论】:
嗯..How to Use Swing Timers
上代码格式的奇怪选择。这似乎是故意的,所以我没有更改它,但它似乎不适合那个 Java Doc 页面标题。 bold 或 italic 怎么样?【参考方案2】:
您尚未在代码中创建 Thread
的对象。您需要创建一个线程,用您的代码覆盖其run()
方法,并通过在您的线程上调用start()
来启动您线程的run()
方法。
private void goButtonActionPerformed(java.awt.event.ActionEvent evt)
new Thread()
public void run()
try
for (int i = 0; i < sim.length; i++)
simulate();
Thread.sleep(500);
catch (Exception e)
e.printStackTrace();
.start();
由于您要从线程更新 gui 元素,您应该使用 invokelater()
。
private void simulate()
SwingUtilities.invokeLater(new Runnable()
public void run()
// Here, we can safely update the GUI
// because we'll be called from the
// event dispatch thread
/* HERE YOUR your simulate() code */
);
我认为应该可以。
【讨论】:
这基本上是 SwingWorker 所做的。它创建一个单独的线程并允许您发布结果,以便在 EDT 上执行代码。 哦,好的。还不知道。我以上是关于更新 JFrame 并使用 Thread.sleep() [重复]的主要内容,如果未能解决你的问题,请参考以下文章
使用框架状态变量更新 JFrame 中的 JPanel 内容