2

저는 Swing 응용 프로그램을 작성 중이며 기능 중 일부는 시각적으로나 청각 적으로 (Mary TTS를 사용하여) 일부 텍스트를 처리하고 출력해야합니다. GUI와 텍스트 처리 클래스가 통신 할 수있는 최선의 방법에 대한 조언이 필요합니다.runnable에서 GUI 업데이트

GUI 클래스는 JPanel의 하위 클래스입니다. 그 안에는 오디오 플레이어에 전달할 텍스트를 준비하는 LineProcesser라는 Runnable을 구현하는 클래스가 있습니다. 내가 EDT (이 최선의 방법이되지 않을 수 있습니다 계속 스레드 실어를 사용하고 있지만 결과를 얻을 것 같다 후).

LineProcessor가 모든 텍스트를 실행하고 각 줄의 끝에서 JTextArea를 업데이트하려고합니다. 또한 특정 지점에서 사용자 입력을 중지하고 대기해야합니다. 사용자 입력이 완료되면 GUI 클래스는 처리를 다시 시작하도록 지시해야합니다.

public class MyPanel extends JPanel { 
    ExecutorService lineExecutor = Executors.newSingleThreadExecutor(); 
    Runnable lineProcessor = new LineProcessor(); 

    public class LineProcessor implements Runnable { 

     private int currentLineNo = 0; 

      public LineProcessor() { 
      // ... 
      } 

      @Override 
      public void run() { 
       // call getText(); 
       // call playAudio(); 
       currentLineNo++; 
      } 
     } 
    } 

    private JButton statusLbl = new JLabel();  
    private JButton mainControlBtn = new JButton(); 

    private void mainControlBtnActionPerformed(ActionEvent evt) { 

     if (mainControlBtn.getText().equals("Start")) { 
          lineExecutor.submit(lineProcessor); 
          mainControlBtn.setText("Running"); 
     } 
    } 
} 

어떻게 LineProcessor은 변경할 필요가 어떻게이 GUI 내에서 일시 정지하고 다시 시작할 수 있습니다 GUI 구성 요소를 알릴 수 있습니다 :

은 다음 코드는 내가 현재 무엇을 보여? 스윙 워커, 속성/이벤트 리스너 또는 다른 것이 필요한지 혼란 스럽습니다. 내가 읽은 예제는 이해가되지만, 여기에있는 코드에 어떻게 적용 할 수 있는지 알 수 없습니다.

답변

6

Swing 호출을 Runnable에 랩핑하고 SwingUtilities.invokeLater(myRunnable);을 통해 EDT에 대기시키기 만하면됩니다. 그게 전부 야. SwingWorker가 필요 없습니다. 예를 들어,

,

public class LineProcessor implements Runnable { 
    private int currentLineNo = 0; 
    Runnable LineProcessor = new LineProcessor(); // won't this cause infinite recursion? 

    public LineProcessor() { 
    // ... 
    } 

    @Override 
    public void run() { 
    // call getText(); 
    // call playAudio(); 
    currentLineNo++; 

    SwingUtilities.invokeLater(new Runnable() { 
     public void run() { 
      // *** Swing code can go here *** 
     } 
    }); 
    } 
} 
+0

+1 좋은 제안입니다. 'invokeLater'는 진행 보고서에 완벽하지만'일시 중지 및 사용자 입력 대기 '부분에'invokeAndWait' 호출이 필요합니다. – Robin

+0

aaaaach이 답변을 주셔서 감사합니다. 모든 답변 (지난 2 개월) 사용 (내 생각) 일반 invokeLater 간단한의 Runnable # 스레드와 비교 매우 복잡한 SwingWorker의 해결 방법을 제안, +1 – mKorbel

+0

내 대답은하지만 둘 훨씬 더 포괄적으로 다른 측면을 해결하기는 OP의 로빈의 또는 mprabhat 년대만큼 좋지 않다 질문. 나는이 대답을 몇 분 안에 삭제할 것이라고 생각한다. 뱀장어의 –

3

당신은 모두 SwingWorker의 및 이벤트 방법론을 사용해야합니다.

  1. 장기 실행 코드는 Swing Worker에 두십시오.
  2. 새 속성 변경 만들기 이벤트, 수신기, 관리자
  3. SwingWorker에서 변경 이벤트가 발생하면 PropertyChangeManager를 호출하여 모든 라이저를 알립니다.
  4. 이벤트와 함께 알림을 받으려는 모든 GUI 구성 요소는 PropertyChangeManager에 자체 등록해야합니다.
  5. 귀하의 PropertyChangeManager는 PropertyChangeListener에의 customProperyChange 메소드를 호출하고 당신이 찾고있는 것은 SwingWorker 인 properyChangeEvent
+0

광산보다 더 깨끗한 OOP 접근법. 1 + –

+0

@HovercraftFullOfEels하지만 복잡해질 수 있습니다 ... 다른 구성 요소가 스레드에서 이러한 이벤트를 갖는 데 관심이 있다고 가정 할 수 있지만 UI 구성 요소는 비 EDT에서 통지되지 않거나 적어도 이벤트를 처리하지 않을 수 있습니다. 실제로 발생 했습니까? 나는이 사건에 대한 당신의 단순한 접근 방식을 선호합니다. – Robin

+0

PropertyChangeListener + SwingWorker +1 – mKorbel

3

을 전달합니다. 이 클래스는 EDT에 정기적 인 업데이트가있는 작업자 스레드에서 작업을 수행 할 수있게 해주 며, 결국 EDT도 업데이트합니다.

몇 가지 예는 SO 및 Swing 자습서에서 사용할 수 있습니다.불과 몇 링크

보고 진행률은 publish 메소드로 수행 할 수 있으며,이 결과는 UI를 업데이트 할 수있는 process 메소드로 전달됩니다. 마지막으로 done 메서드가 호출되어 최종 UI 업데이트를 수행 할 수 있습니다. 멈춤/재시작 기능을

...는 (사용자 입력을 요청하는 예를 들어 도시 JOptionPane) 블로킹 메소드 호출로 doInBackground 방법에 invokeAndWait를 사용할 수있다. 그러나 doInBackground에서 invokeAndWait을 사용하기 시작하면 SwingWorker을 사용하는 것이 과도 할 수도 있으므로 접근 방법을 선택할 수 있습니다. @Hovercraft Full of Eels

+0

도 좋습니다. 1 + –

+0

아주 좋은 대답 +1 – mKorbel

+0

고마워, 지금은 내 코드에서 다른 곳에서 SwingWorker를 사용하고있다. 내 질문에 관련하여, 스레드가 기본 GUI에 제어권을 반환하고 나는 EDT에서 블로킹 호출을하고 싶지 않았기 때문에 실제로'invokeAndWait' 대신에'CountDownLatch'를 사용했습니다. – sonicdeathmonkey