2012-03-24 1 views
2

내가하려고 해요 :이상한 버그 - 어떻게 자바 프로그램을 일시 중지 하시겠습니까?

  1. 표시 JLabel의에서 텍스트,
  2. 2 초 동안
  3. 대기,
  4. 는 다음의 JLabel에 새로운 텍스트를 작성

이 간단해야 ,하지만 이상한 버그가 발생했습니다 : 첫 번째 텍스트는 쓰여지지 않습니다. 응용 프로그램은 2 초 동안 기다렸다가 마지막 텍스트를 표시합니다. 여기에 예제 코드입니다 : "클릭 수"이 코드


private void testButtonActionPerformed(java.awt.event.ActionEvent evt) {  
    displayLabel.setText("Clicked!"); 

    // first method with System timer 

    /* 
    long t0= System.currentTimeMillis(); 
    long t1= System.currentTimeMillis(); 
      do{ 
       t1 = System.currentTimeMillis(); 
      } 
      while ((t1 - t0) < (2000)); 
    */  

    // second method with thread.sleep() 

    try { 
     Thread.currentThread().sleep(2000); 
    } catch (InterruptedException e) {} 

    displayLabel.setText("STOP"); 
} 

, 텍스트 결코 표시되지 않습니다. 방금 2 초 멈춤 후 "중지"텍스트가 나타납니다. 루프 또는 Thread.sleep()과 함께 시스템 타이머를 사용하려고했지만 두 방법 모두 동일한 결과를 제공합니다.

+14

(한숨) EDT (Event Dispatch Thread)를 막지 마십시오. 'Thread.sleep (n)'을 호출하는 대신에 Swing'Timer를 구현하거나'SwingWorker'를 사용하여 장시간 실행되는 작업을 수행 할 수 있습니다. 자세한 내용은 [동시성의 동시성] (http://docs.oracle.com/javase/tutorial/uiswing/concurrency/)을 참조하십시오. –

답변

2

Andrew Thompson의 의견에 대한 자세한 배경 정보를 제공하기 위해 : EDT는 GUI 업데이트를 처리합니다. Thread.sleep(...)을 사용하여 차단하면 해당 업데이트도 차단됩니다. 그래서 첫 번째 텍스트가 표시되지 않습니다. EDT는 라벨에서 업데이트를 수행 할 수 없습니다.

2

다음은 실행중인 작업을 수행하는 실행 가능한 예제입니다. Andrew Thompson의 의견에 따르면 SwingWorker은이 문제를 해결하는 좋은 방법입니다.

기본 보안 주체는 이벤트 발송 스레드를 차단하지 않습니다. 이것이 GUI를 다시 그리며 사용자 상호 작용에 응답하는 스레드입니다. 따라서 EDT에서 계산상의 비용이 많이 드는 작업을 수행하면 GUI가 응답을 멈 춥니 다.

import java.awt.event.ActionEvent; 
import java.awt.event.ActionListener; 
import java.util.concurrent.ExecutionException; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.SwingWorker; 

public class ButtonTest { 
    public static void main(String[] args) { 

     // create a frame and a button 
     JFrame frame = new JFrame(); 
     final JButton button = new JButton("Button"); 
     frame.add(button); 

     // add an action listener to the button 
     button.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent arg0) { 

       // change the button text right away 
       button.setText("Clicked"); 

       // create a SwingWorker which simply waits 2000 milliseconds 
       // simulating a computation being performed 
       SwingWorker<String, Object> worker = new SwingWorker<String, Object>() { 
        @Override 
        public String doInBackground() { 

         // it's safe to call Thread.sleep() here 
         // doInBackground is executed on a separate worker 
         // thread 
         try { 
          Thread.sleep(2000); 
         } catch (InterruptedException e) { 
         } 

         return "Done"; 
        } 

        @Override 
        protected void done() { 

         // done() is executed back on the Swing thread 
         // so it's safe to updated the state of the button 
         try { 
          button.setText(get()); 
         } catch (Exception e) { } 
        } 
       }; 

       // run the worker 
       worker.execute(); 
      } 
     }); 

     frame.setSize(300, 300); 
     frame.setVisible(true); 
    } 
} 
+0

반지 운반자 인 Andrew Thompson, Hovercraft Full of Eels 및 Ulmangt에게 감사드립니다. 마지막으로 SwingWorker를 사용하고 문제를 해결했습니다. – TerraNova993

2

이벤트 디스패처 스레드가 장난입니다. 예상치 못한 UI 동작이 나타날 수 있습니다. 당신이 읽을 수있는 경우 애니메이션이 유형을 할 계획이라면, 앤드류 톰슨도 제안하고 무엇을 읽을 수 있는지 확인, 참조 - 아래 curde-예에서와 같이 더 나은 Filthy rich clients

스윙 Timer을 사용 :

  @Override 
      public void actionPerformed(ActionEvent evt) { 
       if (i <= 1) { 
       messageLabel.setText(messages[i++]); 
       } else { 
       ((Timer)evt.getSource()).stop(); 
       } 
      } 
     }); 
:
왜 타이머를 중지하지

public class DelayTest extends JPanel{ 
    JLabel messageLabel = new JLabel(); 
    JButton actionButton = new JButton("Click Me"); 
    String[] messages = {"Clicked", "Stop!"}; 
    int i=0; 
    public DelayTest(){ 
     super(); 
     add(messageLabel); 
     add(actionButton); 
     actionButton.addActionListener(new ActionListener() { 

      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       Timer timer = new Timer(1000, new ActionListener() { 

        @Override 
        public void actionPerformed(ActionEvent arg0) { 
         if(i<=1) 
          messageLabel.setText(messages[i++]); 
        } 
       }); 
       timer.start(); 

      } 

     }); 
    } 

} 

편집 : (그래, 내가 타이머 등 중지에 대해 걱정하지 않았다 원유입니다)

+0

@ TerraNova993 이것이 가장 쉬운 방법입니다. 스윙 타이머가 +1 이유입니다. – mKorbel

+0

타이머를 멈추는 코드를 추가 할 때? 편집에서 코드가 추가되었습니다. –

+0

@HovercraftFullOfEels - 내 사례에서 언급 한 것은 아닙니다. 맞춤형 솔루션을 제공하고 싶지 않습니다. TerraNova993에 기초를 이해하고 올바르게 이해하기를 원합니다. 편집에서 코드 –

관련 문제