更新JFrame并使用Thread.sleep()

时间:2014-03-21 22:53:43

标签: java multithreading swing

我一直在努力解决一个我现在还不太了解的奇怪问题(我对线程知之甚少):

我有一个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                   
}

2 个答案:

答案 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的部分。