2012-07-03 1 views
3

JLabel이 포함 된 모달 대화 상자가 있습니다. 이 대화 상자는 장기 실행 조회 활동을 수행하는 다른 클래스의 메소드를 호출합니다. 이 조회 클래스가 모달 대화 상자에서 전달되는 JLabel을 업데이트하고 싶습니다.모달 대화 상자에서 JLabel 업데이트 시도

조회 프로세스 및 타이머 내에서 코드 루프에서 JLabel을 업데이트 해 보았습니다. (모달 대화 상자가 실행될 때 Swing 타이머의 actionPerformed 메서드가 호출되지 않는다는 것을 알았습니다.) Timer를 구현 한 이후로, 내 조회 프로세스를 별도의 스레드로 옮겼습니다.

내 조회가 작동하지만 JLabel은 프로세스가 끝날 때까지 다시 그려지지 않습니다. 어떤 도움을 주셔서 감사합니다.

다음은 관련 방법입니다. DictionaryTuple은 List와 String이라는 두 개의 필드를 포함하는 POJO입니다. 그냥 getters 및 setters,하지만 dictionaryThread tupleList에 대한 액세스 권한이; dictionaryThread가 끝날 때까지 여기에 손을 대지 않는다.

public List<DictionaryTuple> findTuples() { 
    tupleList = new ArrayList<DictionaryTuple>(); 
    Thread dictionaryThread = new Thread(this); // This is the long-running lookup thread 
    dictionaryThread.start(); 

    progressTimer = new Timer(); 
    progressTimer.scheduleAtFixedRate(new TimerTask() { 
     @Override 
     public void run() { 
         // progressCaption is updated in dictionaryThread 
      synchronized (progressCaption) { 
       lblProgress.setText(progressCaption); 
      } 
      lblProgress.repaint(); 
      Thread.yield(); 
     } 
    }, 250, 250); 

    try { 
     dictionaryThread.join(); 
    } catch (InterruptedException e) { 
    } finally { 
     progressTimer.cancel(); 
     lblProgress.setText(""); 
     progressCaption = ""; 
    } 
    return tupleList; 
} 

이 변형을 시도해 보았습니다. - 전이나 후입니다

progressTimer.scheduleAtFixedRate(new TimerTask() { 
     @Override 
     public void run() { 
      synchronized (progressCaption) { 
      System.out.println("Fire!"); 
      SwingUtilities.invokeLater(new Runnable() { 
       @Override 
       public void run() { 
        System.out.println("Update"); 
        lblProgress.setText(progressCaption); 
        lblProgress.repaint(); 
       }}); 
      } 
     } 
    }, 250, 250); 
+0

공정한 질문입니다. 두 개의 필드를 포함하는 POJO입니다 : List 과 String. 그냥 getters와 세터. – Elly

+0

감사합니다. 나는 당신이 아직 대답을 받아들이지 않았다는 것을 언급했다. 문제가 해결 되었습니까? 그렇지 않은 경우 문제 행동을 나타내는 [SSCCE] (http://sscce.org/)를 게시하는 것이 좋습니다. –

답변

2

당신은 정확히 당신이 볼에 대화 상자를 설정 우리에게 보여줄 필요가 : 처리가 완료 될 때까지 그 경우, 내부 실행()가 호출 개최 findTuples() 방법으로 전화 하시겠습니까? 이것은 매우 중요합니다.

제안 :

  • 항상 스윙 이벤트 스레드 또는 EDT (이벤트 발송 쓰레드)에 JLabel의를 업데이트합니다.
  • java.util.Timer를 사용하여 Swing 응용 프로그램의 구성 요소를 업데이트하지 마십시오.
  • javax.swing.Timer를 사용하여 Swing 구성 요소를 업데이트 할 수 있지만이 구성 요소를 사용하여 백그라운드 프로세스를 폴링하지 않는 한 여기서는 작동하지 않습니다.
  • 백그라운드 스레딩에 SwingWorker를 사용한 다음 작업자의 게시/프로세스 메소드를 통해 또는 SwingWorker에 추가 된 PropertyChangeListener를 통해 JLabel을 업데이트하십시오.
  • 대화 상자가 실행될 때 실행하고 싶은 모든 메서드를 호출하십시오. 전에 앞에 대화 상자가 표시되도록 설정하십시오.
+0

죄송합니다. 언급하지 않았습니다. 대화 상자에서 버튼을 클릭하면 findTuples() 메서드가 호출됩니다. 물론 대화 상자가 먼저 표시됩니다. – Elly

+1

@ 엘리 : 그것에 대해 "물론"없다. 대화 상자가 차단되므로 대화 상자를 보여주는 *** 앞에 ***라는 코드를 가져와야합니다. 모달 대화 상자에는 다른 가능한 해결책이 없습니다. –

+0

@Elly : 이것이 주요 문제이며, 프로젝트를 진행하는 것을 방해하는 주된 요인이라고 생각합니다. 그래서 이것이 우리가 여기서 작업해야하는 것입니다. 즉, 코드를 마사지하여 당신은이 듣기 코드를 얻을 수 있으며 모달 대화 상자가 표시되기 전에 * 실행중인 코드를 업데이트 할 수 있습니다. 일단 우리가 이것을 알아낼 수 있다면, 당신은 빨리 진행할 것이라고 생각합니다. 따라서 문제에 대해 더 자세히 알려주십시오. 현재 전화 주문이 올바른 순서로 이루어지지 않는 이유에 대해 알려주십시오. 다시 말하지만, 우리가 어떻게이 상황에 적합한 지 보자. –

2

이 데모는 도움이됩니다. 실행 시간이 길어서 다른 스레드를 실행하여 실행하면 다른 스레드가 실행됩니다.


    public static void modalDialogTest() { 
     JDialog dialog = new JDialog((JFrame)null); 
     final JLabel jl = new JLabel("Need some space"); 
     JButton jb = new JButton ("Click me"); 
     Timer t = new Timer(1000, new AbstractAction() { 
      int it = 0; 
      @Override 
      public void actionPerformed(ActionEvent arg0) { 
       // TODO Auto-generated method stub 
       jl.setText("" + it); 
       jl.repaint(); 
       it++; 
      } 

     }); 
     t.start(); 

     AbstractAction wait = new AbstractAction() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       Runnable r = new Runnable() { 
        public void run() { 
         try { 
          Thread.sleep(10000); 
         } catch (InterruptedException e) { 
          e.printStackTrace(); 
         } 
        } 
       }; 
       //r.run(); 
       new Thread(r).start(); 
      } 
     }; 

     jb.addActionListener(wait); 
     dialog.getContentPane().add(jl); 
     dialog.getContentPane().add(jb); 
     dialog.getContentPane().setLayout(new FlowLayout()); 
     dialog.pack(); 
     dialog.setVisible(true); 
     dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE); 
    } 
1

감사합니다. 내가 구현 한 것은 Hovercraft 's이며 SwingWorker를 사용합니다.

내 메서드가있는 사전 클래스는 이제 SwingWorker를 확장합니다. findTuples() 메소드는 doInBackground()가됩니다. 타이머와 내 스레드 코드는 더 이상 필요하지 않습니다.

doInBackground()는 업데이트 된 JLabel에 표시 할 텍스트를 제공하기 위해 "progress"속성과 함께 publish()를 사용합니다.위로 대화 코드

, 처리가 완료 될 때 호출은 사전 인스턴스를 생성하고 감지 (lblProgress 이름)이 JLabel의 변화를 처리하는 PropertyChangeListener를 사용하는 것 :

private void myCallingMethod() { 
    final Dictionary dictionary = new Dictionary(); 

    dictionary.addPropertyChangeListener(new PropertyChangeListener() { 
     @Override 
     public void propertyChange(PropertyChangeEvent event) { 
      List<DictionaryTuple> tupleList; 

      // Is processing complete? 
      if (event.getNewValue() instanceof StateValue 
        && event.getNewValue() == StateValue.DONE) { 
       try { 
        tupleList = dictionary.get(); 
        lblProgress.setText(tupleList.size() + " Tuples Found"); 
       } catch (Exception e) { 
        JOptionPane.showMessageDialog(
          null, 
          "Error in processing dictionary: " 
            + e.getMessage()); 
        tupleList = new ArrayList<DictionaryTuple>(); 
        lblProgress.setText(""); 
       } 

       // Process the results. 
       processTuples(tupleList); 

      } else { 
       // The process isn't done yet. 
       // Is this a request to change lblProgress? 
       if (event.getPropertyName().equals("progress")) { 
        lblProgress.setText((String) event.getNewValue()); 
       } 
      } 
     } 
    }); 

    // Start the dictionary lookup to run asynchronously. 
    dictionary.execute(); 
} 

내가하지 배웠다 SwingWorker.isDone()에 의존하여 SwingWorker의 처리가 완료되었는지 확인합니다. 필자의 경우, PropertyChangeListener는 그 상태에서 두 번 호출되었다 : 마지막 publish() 호출의 결과와 한 번, 그리고 작업이 실제로 완료되었을 때.