2010-02-26 7 views
4

스윙에서 PassiveView 기반 GUI 시스템을 구현하려고합니다. 기본적으로 내 뷰 구현 (실제로 스윙 코드가 포함 된 부분)을 최소화하고 내 Presenter 클래스에서 대부분의 작업을 수행하려고합니다. 발표자는 스윙에 대한 의존성이 없어야하며 "쇼를 운영해야합니다"즉, 무엇을해야 할지를 뷰에 알려야하며 반대의 경우도해야합니다.스윙, 수동보기 및 장기 실행 작업

장기 실행 작업 및 일반적으로 스레드 분리를 처리 할 때 문제가 발생합니다. EDT에서 실행되는 GUI 업데이트와 발표자 로직을 다른 스레드에서 실행하고 싶습니다. GUI를 몇 가지 조치가 발생했음을 발표자를 알려주는 경우

public interface View { 
    void setText(String text); 
} 

public class Presenter { 
    View view; 
    ... 
    public void setTextInVIew() { 
     view.setText("abc"); 
    } 
} 

public class MyFrame implements View { 
    JTextField textField; 
    ... 
    public void setText(final String text) { 
     SwingUtilities.InvokeLater(new Runnable() { 
      public void run() { 
       textField.setText(text); 
      } 
     }); 
    } 
} 

그러나, 나는 밖으로 전환하려는 : 내가 발표자가 꽤 쉽다는 GUI의 일부를 업데이트 할 경우, 그 뭔가를 쓰기

public class Presenter { 
    ... 
    public void buttonPressed() { 
     // shouldn't run on EDT 
    } 
} 

public class MyFrame implements View { 
    JButton button; 
    public MyFrame() { 
     ... 
     button.addActionListener(new ActionListener() { 
      @Override public void actionPerformed(ActionEvent e) { 
       presenter.ButtonPressed(); 
      } 
     }); 
    } 
} 

가의 actionPerformed 코드가 EDT에서 실행되기 때문에, 그래서 presenter.buttonPressed 것이다 : 동부 서머 타임의에 다른 스레드에 반응. 스윙이 SwingWorker의 개념을 가지고 있다는 것을 알고 있습니다. 다른 스레드에서 작업을 실행하고 있지만, 발표자에게 스윙 코드를 삽입해야하며보기가 실행 중입니다. 어떤 아이디어가 이것을 해결하는 방법?

답변

2

당신이 장소에 GUI 코드를 유지하고 단순히 EDT에서 얻을 수있는 작업을 수행 할 다음과 같은 것을, 할 수있는 :

button.addActionListener(new ActionListener() { 
     @Override public void actionPerformed(ActionEvent e) { 
      SwingWorker sw = new SwingWorker() { 
      public Object doInBackground(){ 
       presenter.ButtonPressed();    
       return null; 
      } 
      }; 
      sw.execute(); 
     } 
    }); 
+0

위와 비슷한 패턴을 사용하고 SwingWorker 스레드가 예상대로 작동합니다. +1 – Luhar

+0

최적화 작업으로, 스윙 작업자 호출을 위해 새 스레드를 생성하는 대신 실행 프로그램을 사용하는 것이 좋습니다. –

2

당신은 모든을 피하기 위해 Task API에 관심이있을 수를 상용구. 그렇지 않으면 akf의 솔루션은 괜찮아 보입니다 (SwingWorker에 대한 변수를 만들 필요는 없지만 익명의 새로운 것을 실행할 수 있습니다).

+0

doInBackground() 메소드는 Void (void가 아님)를 반환해야하므로 presenter.ButtonPressed() 호출 후 무언가 (예 : null)를 반환해야합니다. – Adamski

+0

@Adamski : 네 말이 맞아. – JRL

+0

JRL : SwingWorker를 로컬 변수에 할당하는 대신 .execute()를 호출 할 때와 마찬가지로 akf보다 한 줄 더 짧습니다. – Adamski

0

다른 사람들이 설명한 SwingWorker 솔루션에 대한 또 다른 접근법은 스레드 선호도가있는 이벤트 버스를 사용하는 것입니다. 나는 실제로 이것이 당신이 가고있는 디커플링의 유형을위한 최선의 선택이라고 생각합니다.

체크 아웃 : EventBus

버스 아키텍처의 다른 구현이 있지만, EventBus이 인기입니다.

- 갱신 -

그래서 EventBus은 EDT (SwingUtilities.invokeLater()에 대한 명시 적 호출 톤에 비해 더 좋은 많은 비 - EDT에서 프록시의 매우 깨끗한 방법을 제공하는 것입니다 -하지만 기본적으로 일을 EventBus가 많은 알림을 묶어서 단일 EDT 실행 파일에 기록 할 수는 있지만 성능이 향상됩니다.

그러나 이것은 EDT의 이벤트를 프록시 처리하고 작업자 스레드에서 실행해야하는 문제를 해결하지 못합니다. 그러한 짐승의 기초로 사용될 수있는 EventBus에 ThreadSafeEventService 클래스가 있습니다. 예를 들어 ExecutorService와 결합하여 특정 수신기의 특정 이벤트 등록을 처리 할 수 ​​있습니다.

내가 나를 위해 모든이의 키를 추측하는 것은 당신이 와서 어떤 솔루션이 BTW/오프 EDT

에 회전을 캡슐화하는 것을 시도해야한다는 것이다 - 당신이 여기에 대해 물어 보는 것은 정말 비슷합니다 Microsoft의 아파트 스레딩 모델.

+0

이 스레드 유사성을 얻기 위해 명시 적으로 수행해야 할 작업이 있습니까? 나는 EventBus가 코드를 시작하면서 (프레임이 버튼 클릭시 changeEvent를 게시하고 발표자가이 이벤트를 구독 함), 발표자의 이벤트 처리는 EDT –

+0

에서 여전히 좋은 지적입니다. EventBus는 오직 한 방향으로 만 프록 싱을 수행합니다 (이벤트가 EDT에서 시작된 경우 EDT에 자동으로 프록시 됨). 두 방향으로 작업해야하는 것처럼 들립니다 (EDT에서 시작된 이벤트는 EDT에서 청취자에게 전달되어야 함). 나는 이것에 조금 확장하기 위하여 포스트를 새롭게 할 것이다. –

0

확인 - 내가 당신을 위해 다른 옵션을 가지고 : Spin

는 궁극적으로 이러한 솔루션의 모든 스레드 사이의 통화를 프록시한다. 최종 목표는 뻔뻔한 코드가 필요없는 솔루션을 찾는 것입니다. 예를 들어 모든 청취자를 연결하여 적절한 작업자 스레드에 있는지 확인한 다음 그렇지 않은 경우 ExecutorService로 프록시 할 수 있습니다. 그러나 그것은 대대적 인 번거 로움입니다. 비즈니스와 뷰 객체 사이의 레이어에서 해당 프록시를 가져 오는 것이 훨씬 더 좋습니다. 바인딩/리스너/원하는 모든 것을 레이어라고합니다.

관련 문제