2013-05-31 2 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);을 호출하고 있습니다. 즉, 메소드가 종료 될 때만 - repaint()가 실행됩니다 (나중에 어느 시점에서).

그 때까지는 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()> 

이것은 당신이해야 할 일이다 (I 컴파일하거나 테스트하지 않았다) :

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에 표시된 텍스트가 즉시 업데이트되지 않습니다. 대신 텍스트 필드의 내부 변수가 변경되며 스윙 큐에 다시 그리기가 필요함을 알립니다. 이것은 이벤트 대기열을 통과하므로 함수가 반환 된 후에 만'repaint()'*를 통해 실행됩니다. –

+0

@AlexGittemeier 답변과 의견에 따라 코드를 변경했습니다 (게시물 참조). 업데이트 된 코드는 사용자의 의견에서 이해할 수있는 내용을 반영하지만 오류를 수정하지는 않습니다. 'repaint();' 메소드에서 반환 된 _after_이라고합니다. 모든 것이 제대로 업데이트되지 않아야합니까? – Aaron

+2

@Aaron 이것은 여전히 ​​같은 스레드에서 실행 중입니다. 이제 mouseClicked()'->'updateOne()'->'exit updateOne()'->'enter ...'->'exit mouseClicked()'-> ...-> >'execute repaint()' – Xeon

관련 문제