2013-04-09 3 views
1

저는 GUI를 프로그래밍 중이 었습니다. 버튼을 누르면 계산 시간이 길어졌습니다. 계산이 실행되는 동안, 여전히 실행중인 계산의 중간 결과를 사용하여 JLabel에 기록하고자했습니다. 그러나 GUI는 계산이 완료되기 전에 사용자가 조작 할 수 없습니다. 이 같은 에서 처음으로 내가하고 있던 일 : 계산이 완료된 후GUI를 차단하는 동안 스윙 구성 요소를 업데이트

(1)

public class GUI extends JFrame { 

    JLabel label = new JLabel("Status: "); 
    public GUI(){...} 

    public void calculate() { 
     for(int i = 0; i < 10; i++) { 
      String one = calculationPartOne(i); 
      label.setText("Status: " + one); 
      label.repaint(); //* 
      calculationPartTwo(i); 
     } 
    } 
} 

이 작동하지 않았다, JLabel의 만 업데이트 할 것입니다. 또한 주석 처리 된 행에 관련된 모든 구성 요소를 .repaint() 및 .validate()하려고 시도했지만 아무 것도 수행하지 않았습니다. 그래서 Google/StackoOverflow를 시도하고 검색 한 후에 마침내 해결책을 찾았지만 위의 이유가 이해되지 않습니다. GUI를 차단하기를 원했기 때문에 당연히 같은 스레드에서 계산을 실행했습니다. 그러나 GUI를 다시 그리는 메소드를 호출하면 (계산이 중지되는 동안 계산이 중지됨) 작동하지 않으며 그 이유를 이해할 수 없습니다. 누군가 설명 할 수 있습니까?

결국, 나는 계산을 할 때 SwingWorker 클래스를 사용했고 계산하는 동안 JLabel을 업데이트하는 함수를 사용했습니다. 그러나 GUI를 차단해야 할 때 SwingWorker를 실행하기 전에 구성 요소를 모두 비활성화하고 SwingWorker에서 계산을 마친 후 모든 구성 요소를 다시 활성화 할 수있게되었습니다. 그래서 SwingWorker를 사용하여 EDT를 차단하지 않고 모든 것을 비활성화하여 EDT를 차단합니다. 이것은 나에게 정말로 역설적 인 것처럼 보인다.

public class GUI extends JFrame { 
    JLabel label = new JLabel("Status: "); 
    //I didn't use a list, but it works to illustrate it here 
    List<Component> GUIComponents = ...; 
    public GUI() {...} 

    public void calculate() { 
     SwingWorker<Void, String> worker = new SwingWorker<Void, String>() { 
      protected Void doInBackground() throws Exception { 
       for(int i = 0; i < 10; i++) { 
        String one = calculationPartOne(i); 
        publish(one); 
        calculationPartTwo(i); //** 
       } 
      } 

      protected void done() { 
       setEnableGUI(true); 
      } 

      protected void process(List<String> chunk) { 
       label.setText(chunk.get(chunk.size() - 1)); 
      } 
     }; 
     setEnableGUI(false); 
     worker.execute(); 
    } 

    public void setEnableGUI(boolean e) { 
     for(Component c : GUIComponents) { 
      c.setEnabled(e); 
     } 
    } 

    //** 
    public void calculationPartTwo() {...} 
} 

이 작동 : 여기

내가 지금 무슨의 개요입니다.

누군가가 분명히 밝힐 수 있기를 바랍니다. 이 솔루션은 잘못되었습니다.

+0

SwingWorkers 메서드가 처리하고 게시하는 similair Q & A는 무리가 있습니다. setProgress가 가능하면 모든 가능한 모서리에서 JComponent를 스윙한다고 올바르게 알립니다. – mKorbel

답변

1

왜 잘못 되었나요? GUI 스레드는 사용자 이벤트에만 응답하기위한 것이므로 백그라운드에서 무거운 짐을 짊어 져야합니다. SwingWorker로 수행하는 작업입니다.

또한 사용자가 구성 요소를 변경하지 못하게하는 가장 좋은 방법은 정확히 수행하는 것입니다. 즉, 중량 해제 해제를 시작하기 전에 구성 요소를 사용 중지하고 완료되면 사용 가능하게 설정하십시오.

모달 대화 상자에 계산 결과를 표시하는 것은 부모 창 위에 팝업되어 차단되는 JDialog입니다. 이 대화 상자에서 중간 결과와 진행률을 표시 한 다음 계산이 완료되면 대화 상자가 닫히고 차단 된 UI의 차단을 해제합니다. 이렇게하면 모든 gui 구성 요소를 루프 내에서 개별적으로 비활성화해야하는 번거 로움을 덜어 줄뿐만 아니라 "취소"버튼을 사용하여 즉시 작업을 중단 할 수있는 옵션을 제공합니다.

+0

이것을 확인해 주셔서 감사합니다. 나는 그것이 나에게 직관적이지 않은 것처럼 보였기 때문에 주로 잘못된 것으로 판명되었지만, 아마도 멀티 스레드 코드를 많이 작성할 필요가 없었기 때문에 가능했다. 모달 다이얼 우지는 SwingWorker의 .get() 메소드에서도 언급되었지만 실제로는 GUI 자체에 상태가 포함되기를 원했습니다. – Maro

1
(GUI를 업데이트하는 동안 계산을 중지합니다) 작동하지 않았다 계산 -inbetween- GUI를 다시 칠하기 위해 어떤 방법을 호출 그러나

, 나는 그 이유를 이해하지 않습니다. 누군가 설명 할 수 있습니까?

repaint() 요청은 RepaintManager에 의해 처리되며 즉시 수행되지 않습니다. RepaintManager는 기본적으로 다시 그리기를 예약합니다. 다시 칠하기는 EDT에서 수행되므로 EDT가 사용 가능할 때까지 수행 할 수 없습니다.

그래서 저는 SwingWorker를 사용하여 EDT를 차단하지만, 모든 것을 비활성화하여 EDT를 차단하도록 "가짜"합니까? 이것은 나에게 정말로 역설적 인 것처럼 보인다.

항상 미정의 JProgressBar를 사용할 수 있습니다. How to Use Progress Bars을 참조하십시오.

또는 어쩌면 Disabled Glass Pane 접근 방식을 사용하는 것이 좋습니다.

경우에 따라 사용할 수 있습니다

label.paintImmediately(...); 

이 구성 요소의 다시 그리기를 강제로. 그러나 GUI를 사용하지 못하게하는 문제는 여전히 있으므로 실제로 사용해야 할 해결책은 아닙니다.

+0

paintImmediately()는 EDT에서 원하는 Rectange를 다시 그리기 위해 적절한 방법이 될 수 없습니다. (귀하의 GLassPane +1) – mKorbel

+0

감사합니다. RepaintManager에 대해 알지 못했지만, 왜 필요하지만 생각하고 있는지 100 % 확신하지 못했습니다. 그것은 말이 될 수 있습니다. 또한 Intresting Glass Pane 링크에 감사드립니다. – Maro

+0

EDT에서 코드가 실행되도록 버튼을 클릭하면 "calculate"메서드가 호출됩니다. RepaintManager에 페인트 요청을 추가하는 대신 즉시 페인팅을 수행합니다. – camickr

관련 문제