1

사용자에게 I/O 작업의 진행 상태를 알려주고 싶습니다. 현재 I/O를 시작하고 완료된 후에 중지하기 전에 내가 시작하는 내부 클래스가 있습니다. 그것은 다음과 같습니다CPU를 사용하는 진행 바 업데이트 프로그램

class ProgressUpdater implements Runnable { 

     private Thread thread; 
     private long last = 0; 
     private boolean update = true; 
     private long size; 

     public ProgressUpdater(long size) { 
      this.size = size; 
      thread = new Thread(this); 
     } 

     @Override 
     public void run() { 
      while (update) { 
       if (position > last) { 
        last = position; 
        double progress = (double) position/(double) size * 100d; 
        parent.setProgress((int) progress); 
       } 
      } 
     } 

     public void start() { 
      thread.start(); 
     } 

     public void stop() { 
      update = false; 
      parent.setProgress(100); 
     } 
    } 

parent 내 UI 내 참조이며, position/O를 우리가 진행 한 얼마나 멀리 I에서 나타내는 내 외부 클래스의 필드입니다. 때로는 I/O가 이전 증분 업데이트를 완료하기 전에 내 업데이터를 완료하고 중지하기 때문에 중지 할 때 진행률을 100 %로 설정합니다. 그것은 단지 그것이 100 %에 있음을 보장합니다. 순간

,이 작동하고, 나는이처럼 사용

ProgressUpdater updater = new ProgressUpdater(file.length()); 
updater.start(); 
//do I/O 
//... 
updater.stop(); 

문제는 루프가 꽤 심하게 CPU를 먹는 것입니다. 나는 거기에 기다림 (알림/알림)을 던지려고했지만 기다/알림을 사용할 때 내 스레드를 매달 렸을 때 내가 뭘하는지 모르겠다. 이렇게 많은 CPU주기를 사용하지 못하게하려면 어떻게해야합니까?

+0

뭔가 나에게 잘못 보인다. 진행이 완료되지 않은 경우에도 루핑됩니다. 다시 반복 할 기다림이나 조건이 없습니다. 항상 실패 할지라도 백만 번 반복하여 'if (position> last)'테스트를 반복합니다. 이 일에는 어떤 종류의'sleep()'이 있어야합니다. – Havenard

+1

당신은 즉시 물건을 업데이트 할 필요가 없습니다, 당신은 100ms마다 업데이 트하고 사용자에게 그것은 실시간 업데이 트와 다를 수 있습니다. – Havenard

+0

@Havenard 나는 당신의 제안으로 끝났고, 나는 그곳에 잠을 더줬고 지금은 꿈처럼 작동합니다. 잊어 버린이 오래된 질문에 대답하고 싶다면 받아 들일 것입니다. – Logan

답변

6

SwingWorker을 사용해야합니다. 기본적으로 SwingWorker이 제공하는 백그라운드 스레드의 모든 IO를 수행하며 진행 상황을 스윙 스레드에보고하는 기본 제공 방법이 있습니다.

그 위치를 업데이트 할 때마다 계속 진행된 폴링 진행이 아닌 자동으로 진행 상황을 업데이트 할 수 있습니다.

Swingworker Timeout 또는 SwingWorker with FileReader에서 도움이되는지 확인하십시오.

대체 솔루션 당신이 SwingWorker을 사용하지 않으려면, 아마, 해당 position 값을 업데이트하는하는 것 같은 호출로 직접 진행 표시 줄을 업데이트 :

SwingUtilities.invokeLater(new Runnable() { 
    @Override public void run() { 
     getMyProgressBar().setValue(position); 
    } 
}); 

진행률 표시 줄의 최대 값이 파일 크기가되도록 설정했다고 가정합니다.

+0

IO가 백그라운드 스레드에 이미 있습니다. 중요합니까? – Logan

+0

응용 프로그램이 주로 스윙 응용 프로그램이라면'SwingWorker'가 당신이 한 일을하는 "정상적인"방법이라고 말할 수 있습니다. 당신은 분명히 당신이 좋아하는 다른 배경 응용 프로그램으로 그것을 할 수 있습니다. 다른 방법으로 여기에서 약간 편집 할 것입니다. –

+1

@LoganDam 아니요,하지만 EDT가 아닌 다른 스레드에서 UI 구성 요소를 만들거나 수정 한 적이 없으므로 호출을 UI로 다시 동기화하는 것이 더 쉬울 것입니다. IO를'SwingWorker '를 사용하도록 변환하는 것은 정말로 사소한 일입니다. [this] (http://stackoverflow.com/questions/15668715/how-to-use-the-swing-timer-to-delay-the-loading-of-a-progress-bar/15669717#15669717)를 확인하십시오. 예제 예를 들어 – MadProgrammer

5

먼저 Java에서 GUI (Swing 구성 요소)를 업데이트하려면 Thread을 절대 사용하지 마십시오. 대신 javax.swing.Timer 또는 javax.swing.SwingWorker을 사용하십시오. 그리고 기본 I/O 작동을 위해서는 ProgressMonitorInputStream을 사용하십시오. 파일을 읽고 아래의 코드를 살펴 JTextArea에와 progrressbar..Have 함께 표시
로 간단한 예 :

enter image description here

import javax.swing.*; 
import java.awt.*; 
import java.awt.event.*; 
import java.util.List; 
import java.io.*; 
import java.beans.*; 
class ProgressBarFrame extends JFrame 
{ 
    JProgressBar progressBar; 
    int BUFFERSIZE = 10; 
    JTextArea textArea; 
    MyWorker worker; 
    private void createAndShowGUI() 
    { 
     progressBar = new JProgressBar(0,100); 
     progressBar.setStringPainted(true); 
     JButton button = new JButton("Read File"); 
     textArea = new JTextArea(30,100); 
     JScrollPane jsp = new JScrollPane(textArea); 
     Container c = getContentPane(); 
     c.add(jsp); 
     c.add(progressBar,BorderLayout.NORTH); 
     c.add(button,BorderLayout.SOUTH); 
     worker = new MyWorker(); 
     button.addActionListener(new ActionListener() 
     { 
      @Override 
      public void actionPerformed(ActionEvent evt) 
      { 
       textArea.setText(""); 
       progressBar.setValue(0); 
       if (worker.getState()== SwingWorker.StateValue.DONE || worker.getState()==SwingWorker.StateValue.STARTED) 
       { 
        worker.cancel(true); 
        worker = new MyWorker(); 
       } 
       worker.execute(); 

      } 
     }); 
     pack(); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setVisible(true); 
    } 
    class MyWorker extends SwingWorker<Void, String> 
    { 
     MyWorker() 
     { 
      addPropertyChangeListener(new PropertyChangeListener() 
      { 
       public void propertyChange(PropertyChangeEvent evt) 
       { 
        if ("progress".equals(evt.getPropertyName())) 
        { 
         progressBar.setValue((Integer)evt.getNewValue()); 
        } 
       } 
      }); 
     } 

     @Override 
     public Void doInBackground() throws IOException 
     { 
      File file = new File("ProgressBarFrame.java"); 
      long size = file.length(); 
      long temp = 0; 
      BufferedInputStream bfin = new BufferedInputStream(new FileInputStream(file)); 
      byte[] buffer=new byte[BUFFERSIZE]; 
      int totalRead = -1; 
      while ((totalRead=bfin.read(buffer))!=-1 && ! isCancelled()) 
      { 
       temp = temp + totalRead; 
       publish(new String(buffer)); 
       if (bfin.available()<BUFFERSIZE && bfin.available()!= 0) 
       buffer = new byte[bfin.available()]; 
       else if(bfin.available()==0) 
       buffer = new byte[1]; 
       else 
       buffer=new byte[BUFFERSIZE]; 
       setProgress((int)((temp/(float)size) * 100)); 
       try{Thread.sleep(1);}catch(Exception ex){} 
      } 
      setProgress(100); 
      return null; 
     } 
     @Override 
     protected void process(List<String> chunks) 
     { 
      for (String value : chunks) 
      { 
       textArea.append(value); 
      } 
     } 
    } 
    public static void main(String st[]) 
    { 
     SwingUtilities.invokeLater(new Runnable() 
     { 
      @Override 
      public void run() 
      { 
       ProgressBarFrame pf = new ProgressBarFrame(); 
       pf.createAndShowGUI(); 
      } 
     }); 
    } 
}