我一直在努力解决一个我现在还不太了解的奇怪问题(我对线程知之甚少):
我有一个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
}
答案 0 :(得分:0)
您尚未在代码中创建Thread
的对象。您需要创建一个线程,用您的代码覆盖其run()
方法,并通过在您的线程上调用run()
来启动线程的start()
方法。
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-element,因此应使用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 */
}
});
}
我认为这应该有用。
答案 1 :(得分:0)
ActionListener中的代码在Event Dispatch THread上执行。 Thread.sleep(...)导致EDT进入睡眠状态,因此GUI无法重新绘制,直到整个循环执行完毕。
阅读Concurrency上的Swing教程中的部分以获取更多信息。
如本教程所述, Ones解决方案是使用SwingWorker
然后&#34;发布&#34;结果如所需。
另一种方法是使用Swing Timer
来安排更新。本教程还有一个关于How to Use Swing Timers
的部分。