2013-05-31 48 views
0

我想弄清楚为什么文本字段没有更新。我知道使用SwingWorker可能会解决这个问题,但我不明白为什么它不起作用。JTextField不使用Thread.sleep更新()

public class waitExample { 

private JFrame frame; 
private JTextField txtLeadingText; 
private String one = "update string 1"; 
private String two = "update string 2"; 
private String three = "update string 3"; 

public static void main(String[] args) { 
    EventQueue.invokeLater(new Runnable() { 
     public void run() { 
      try { 
       waitExample window = new waitExample(); 
       window.frame.setVisible(true); 
      } catch (Exception e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
} 

public waitExample() { 
    initialize(); 
} 

private void initialize() { 
    frame = new JFrame(); 
    frame.setBounds(100, 100, 450, 300); 
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

    txtLeadingText = new JTextField(); 
    txtLeadingText.setHorizontalAlignment(SwingConstants.CENTER); 
    txtLeadingText.setText("leading text"); 
    frame.getContentPane().add(txtLeadingText, BorderLayout.SOUTH); 
    txtLeadingText.setColumns(10); 

    JButton btnClickMeTo = new JButton("CLICK ME TO UPDATE TEXT"); 
    btnClickMeTo.addMouseListener(new MouseAdapter() { 
     @Override 
     public void mouseClicked(MouseEvent arg0) { 

      try { 

       updateOne(); 
       Thread.sleep(1000); 
       updateTwo(); 
       Thread.sleep(1000); 
       updateThree(); 
       Thread.sleep(1000); 
       updateLast(); 
      } catch (InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    }); 
    frame.getContentPane().add(btnClickMeTo, BorderLayout.CENTER); 
} 

private void updateOne() { 

    txtLeadingText.setText(one); 
} 

private void updateTwo() { 

    txtLeadingText.setText(two); 
} 

private void updateThree() { 

    txtLeadingText.setText(three); 
} 

private void updateLast() { 

    txtLeadingText.setText("default text"); 
    } 
} 

据我所知,默认的线程将阻止任何GUI更新。这应该不重要,因为我在Thread.sleep之前设置了textField。 为什么不更新文本字段?不应该设置文本,然后线程等待?

编辑:根据答案,上述代码已被更新。

回答

1

GUI事件循环更新屏幕,但它不能更新屏幕,直到您返回。

我建议你避免在GUI事件线程中做任何阻塞操作。

3

您正在调用EDT上的Thread.sleep(1000);。这意味着当你的方法结束时 - 只有重绘()会触发(稍后的某个时间点)。

在此之前,您的GUI被冻结。

认为这是在一个线程中去(这样的处理非常简单):

txtLeadingText.setText(one); 
Thread.sleep(1000); 
txtLeadingText.setText(two); 
Thread.sleep(1000); 
txtLeadingText.setText(three); 
Thread.sleep(1000); 
... 
<returning from updateText()> 
<processing other events on button click> 
... 
// some time later 
<Swing finds out that GUI needs repaint: calls rapaint()> 

这是你应该做的(我没有编译或测试):

public class MyRunnable implements Runnable { 
     private List<String> strsToSet; 
     public MyRunnable(List<String> strsToSet) { 
      this.strsToSet = strsToSet; 
     } 
     @Override 
     public void run() { 
      try { 
       if(strsToSet.size() > 0) { 
        final String str = strsToSet.get(0); 
        SwingUtilities.invokeLater(new Runnable() { 
         @Override 
         public void run() { 
          txtLeadingText.setText(str); 
         } 
        }); 

        Thread.sleep(1000); 
        List<String> newList = new LinkedList<String>(strsToSet); 
        newList.remove(0); 
        new Thread(new MyRunnable(newList)).start(); 
       } 
      } 
      catch(InterruptedException e) { 
       e.printStackTrace(); 
      } 
     } 
    } 
    new Thread(new MyRunnable(Arrays.asList(one, two, three))).start(); 

在Swing中很难做到,但与动态语言(如Groovy)相比,它会如此简单(您将更好地掌握正在发生的事情):

edt { 
     textField.setText(one) 
     doOutside { 
      Thread.sleep(1000); 
      edt { 
       textField.setText(two) 
       doOutside { 
        Thread.sleep(1000); 
        edt { 
         textField.setText(three) 
        } 
       } 
      } 
     } 
    } 
+1

为了进一步解释:当您调用类似'txtLeadingText.setText(one)'的函数时,GUI上显示的文本不会立即更新。相反,文本字段的内部变量将会更改,并且它还会通知Swing队列它需要重新绘制。因为这经历了事件队列,所以它只能在函数返回后通过'repaint()'*运行。 –

+0

@AlexGittemeier根据答案和您的评论,我已经更改了代码(请参阅帖子)。更新后的代码反映了我从您的意见中了解的内容,但它仍不能解决错误。如果'重绘();'被称为_after_从方法返回,不应该一切正确更新? – Aaron

+2

@Aaron这仍然是在同一个线程中执行。现在它是这样的:'enter mouseClicked()' - >'enter updateOne()' - >'exit updateOne()' - >'enter ...' - >'exit mouseClicked()' - > ...- >'execute repaint()' – Xeon