更新 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 页面标题。 bolditalic 怎么样?【参考方案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 内容

调整JFrame大小后更新JFreeChart / JPanel

JFrame / JPanel不会更新重绘或重新验证

如何在 C# 中模拟鼠标按钮按下并按住

JPanel 在调整 Jframe 大小之前不会更新

如何更新线程中的JFrame标签? - Java