2016-06-10 2 views
0

이 커뮤니티는 새로운 기능입니다.스윙 작업자 및 GUI 업데이트

SwingWorker와 GUI와의 관계에 대해 묻고 싶습니다.

SwingWorker에 대한 몇 가지 대답이 있습니다. 이미 많은 도움을 얻었으며 유용한 조언을 듣고 있습니다.

이제는 지정된 디렉토리에서 파일 및 폴더의 수를 계산하는 기본 응용 프로그램에 대해 작성한 코드를 게시하고 싶습니다.

검색에 많은 시간이 걸릴 수 있으므로 프로세스 중에 진행률 표시 줄을 표시하고 싶습니다. 또한 단추를 클릭하거나 진행률 표시 줄이있는 프레임을 닫아서 카운트 프로세스를 중지 할 수있는 기능을 사용자에게 제공하고 싶습니다. 여기

코드에 대한 몇 가지 질문은 다음이 게시되어 있습니다 : 그것은 더 나은 곳이되어

  • ()를 호출 SwingWorker를위한 방법은 WaitingFrame 생성자의 마지막 명령이 실행?
  • WaitingFrame에 대한 dispose() 메소드가 SwingWorker의 done() 메소드에서 호출되었습니다. 맞습니까? 계산 프로세스가 매우 빠르면 대기 프레임이 실제로 표시되기 전에 dispose 메서드를 호출 할 수 있습니까? 그 결과 두 개의 열린 프레임이 있습니다 ...
  • 프로세스를 중단하고 사용자에게 표시되는 메시지 대화 상자를 관리하는 더 좋은 방법이 있습니까? 나는 내 목적을 달성하기 위해 유효하고, 중단이 개 부울 변수 ...

그리고 여기에 사용되는 코드 : 당신은 컴파일 할 수 있도록

import java.awt.*; 
import java.awt.event.*; 
import java.io.File; 
import java.io.IOException; 
import javax.swing.*; 
import javax.swing.border.*; 
public class CountFiles 
{ 
    public static void main(String[] args)throws Exception 
    { 
     SwingUtilities.invokeLater(new Runnable(){ 
      public void run(){ 
       try 
       { 
        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); 
        new CountFilesFrame().setVisible(true); 
       } 
       catch(Exception ex){ 
        ex.printStackTrace(); 
       } 
      } 
     }); 
    } 
} 
class CountFilesFrame extends JFrame 
{ 
    private JTextField field; 
    public CountFilesFrame() 
    { 
     super("Conta File e Cartelle"); 
     setDefaultCloseOperation(EXIT_ON_CLOSE); 
     setResizable(false); 
     JPanel pane=(JPanel)getContentPane(); 
     pane.setBackground(Color.WHITE); 
     pane.setBorder(new EmptyBorder(5,20,5,20)); 
     JPanel center=new StyledPanel(pane,BorderLayout.CENTER,new FlowLayout(FlowLayout.LEFT,5,10)),bottom=new StyledPanel(pane,BorderLayout.SOUTH,new FlowLayout(FlowLayout.LEFT,20,0)); 
     // Center panel 
     center.add(new JLabel("Cartella :")); 
     String text=""; 
     try{ 
      File folder=new File("../"); 
      text=folder.exists()?folder.getCanonicalPath():""; 
     } 
     catch(Exception ex){} 
     field=new JTextField(text,25); 
     center.add(field); 
     // JTextArea 
     String newLine=System.getProperty("line.separator"),message="Scegliere la cartella da cui far partire la ricerca."+newLine+ 
     "Sara' contato il numero di file e di cartelle presenti "+newLine+"nella directory inserita e in tutte le sottocartelle"; 
     JTextArea area=new JTextArea(message); 
     area.setEditable(false); 
     area.setFont(field.getFont()); 
     pane.add(area,BorderLayout.NORTH); 
     // Bottom panel 
     bottom.add(new JButton(new AbstractAction("Cambia Cartella"){ 
      public void actionPerformed(ActionEvent e){ 
       changeDirectory(); 
      } 
     })); 
     bottom.add(new JButton(new AbstractAction("Inizia ricerca"){ 
      public void actionPerformed(ActionEvent e){ 
       new WaitingFrame(CountFilesFrame.this); 
      } 
     })); 
     pack(); 
     setLocationRelativeTo(null); 
    } 
    public void changeDirectory() 
    { 
     JFileChooser chooser=new JFileChooser(field.getText()); 
     chooser.setDialogTitle("Cambia Cartella"); 
     chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 
     if(chooser.showDialog(this,"Scegli")==JFileChooser.APPROVE_OPTION) 
     { 
      try 
      { 
       File selected=chooser.getSelectedFile(); 
       if(selected.exists())field.setText(selected.getCanonicalPath()); 
      } 
      catch(Exception ex){} 
     } 
    } 
    private class WaitingFrame extends JFrame 
    { 
     private Counter counter; 
     public WaitingFrame(CountFilesFrame f) 
     { 
      super("Ricerca File"); 
      setDefaultCloseOperation(DISPOSE_ON_CLOSE); 
      addWindowListener(new WindowAdapter(){ 
       public void windowClosing(WindowEvent e){ 
        stopCounter(); 
       } 
      }); 
      setResizable(false); 
      JPanel pane=(JPanel)getContentPane(),buttonPanel=new StyledPanel(pane,BorderLayout.SOUTH,new FlowLayout(FlowLayout.CENTER,0,10)); 
      JLabel label=new JLabel("Conteggio in corso...",JLabel.CENTER); 
      label.setBorder(new EmptyBorder(0,0,10,0)); 
      pane.add(label,BorderLayout.NORTH); 
      pane.setBackground(Color.WHITE); 
      pane.setBorder(new EmptyBorder(10,40,0,40)); 
      JProgressBar progressBar=new JProgressBar(0,100); 
      progressBar.setBorderPainted(false); 
      progressBar.setIndeterminate(true); 
      pane.add(progressBar,BorderLayout.CENTER); 
      buttonPanel.add(new JButton(new AbstractAction("Annulla"){ 
       public void actionPerformed(ActionEvent e){ 
        stopCounter(); 
       }  
      })); 
      while(pane.getSize().width!=pane.getPreferredSize().width)pack(); 
      setLocationRelativeTo(null); 
      setVisible(true); 
      (counter=new Counter()).execute(); 
     } 
     public void stopCounter() 
     { 
      counter.interrupt(); 
      counter.cancel(true); 
     } 
     private class Counter extends SwingWorker<Void,Void> 
     { 
      private boolean valid=true,interrupted=false; 
      private int filesNumber=0,foldersNumber=0; 
      protected Void doInBackground() 
      { 
       File folder=new File(field.getText()); 
       if(!folder.exists()||!folder.isDirectory())valid=false; 
       else countFiles(folder); 
       return null; 
      } 
      protected void done() 
      { 
       dispose(); 
       if(interrupted)return; 
       else if(!valid)JOptionPane.showMessageDialog(CountFilesFrame.this,"Inserire una cartella valida","Percorso specificato errato",JOptionPane.ERROR_MESSAGE); 
       else JOptionPane.showMessageDialog(CountFilesFrame.this,"Sono stati trovati "+(foldersNumber-1)+" cartelle e "+filesNumber+" file","Ricerca completata",JOptionPane.INFORMATION_MESSAGE); 
      } 
      private void countFiles(File file) 
      { 
       if(file.isDirectory()) 
       { 
        foldersNumber++; 
        for(File nested:file.listFiles())countFiles(nested);    
       } 
       else filesNumber++; 
      } 
      public void interrupt() 
      { 
       interrupted=true; 
      } 
     } 
    } 
} 
class StyledPanel extends JPanel 
{ 
    public StyledPanel(JPanel parent,String position,LayoutManager layout) 
    { 
     super(layout); 
     setBackground(Color.WHITE); 
     parent.add(this,position); 
    } 
} 

나는 모든 응용 프로그램 코드를 게시 그것을 실행하십시오.

미리 도움 주셔서 감사합니다.

추신 : 나는 인터페이스 언어를 변경하지 않았습니다. 유감입니다. 또한, 나쁜 영어에 대해 유감스럽게 생각합니다 ...

+0

* "인터페이스 언어가 변경되지 않았습니다."* 문제와 관련이없는 것처럼 보이므로 왜 신경 써야합니까? 모든 클래스 이름과 속성은 영어로되어 있습니다. 유용합니다. :) –

답변

1

SwingWorker에 대한 execute() 메소드 호출은 WaitingFrame 생성자의 마지막 명령어입니다. 더 좋은 곳이 있습니까?

전화하는 방법에 아무런 문제가 없습니다.

WaitingFrame의 dispose() 메소드가 SwingWorker의 done() 메소드에서 호출되었지만 맞습니까? 카운트 프로세스가 매우 빠르면 대기 프레임이 실제로 표시되기 전에 dispose 메서드를 호출 할 수 있습니까? 결과적으로 두 개의 열린 프레임이 생깁니다 ...

정확하고 설명하는 상황이 발생할 수 없습니다. SwingWorker.done()은 지연 호출을 통해 EDT에서 호출되며 SwingWorker (EDT에서)을 구성하기 전에 이미 JFrame.setVisible(true)을 호출했습니다.

multiple frames 대신 사용자 입력을 차단하려는 경우 (예 : here) 대화 상자를 사용하는 것이 좋습니다.

프로세스를 중단하고 사용자에게 표시되는 메시지 대화 상자를 관리하는 더 좋은 방법이 있습니까? 내 목적을 달성하기 위해 유효하고 중단 된 두 가지 부울 변수를 사용했습니다 ...

현재 코드가 위험에 가까운 스레드 안전하지 않은 경우를 고려하면 확실히 더 좋은 방법입니다. EDT와 스윙 작업자가이 두 멤버에 액세스해야하는 경우 boolean 대신 AtomicBoolean을 사용하는 것이 좋습니다.

어딘가에 interrupted 플래그를 확인하고 파일 목록이 변경되면 루프를 종료해야합니다.

세분화 된 GUI 업데이트의 경우 SwingWorker.doInBackground()에있는 SwingUtilities.invokeLater 전화로 임의의 스윙 코드를 래핑 할 수도 있습니다. 이 작업은 본질적으로 done()이 호출 된 경우와 동일한 효과가 있지만 호출 된 횟수와 횟수를 제어합니다. 코드 예제는 here을 확인하십시오. 자신의 코드는 main() 메소드 내부의 주 스레드에서 EDT로 실행을 전달하기 위해이 작업을 수행합니다.이 코드 패턴의 이유는 모든 스윙 코드가 EDT에서 실행되어야한다는 것입니다.

+0

우선, 여러분의 많은 제안에 감사드립니다! – Ansharja

+0

우선, 당신의 제안에 대해 정말 고마워요! 마지막 점에 대해 말씀하신 내용을 적용 해 보겠습니다. 대화 상자에 관해서는 모달 대화 상자를 사용해 보았지만 setVisible을 호출해도 프로세스가 시작되지 않습니다. 그 경우 setVisible() 전에 execute()를 호출해야합니까? 나는 두 번째 점에서 물어 본 것에 대해 더 위험했을 것이라고 생각했다 ... – Ansharja

+0

모달 대화 상자는'setVisible (true)'이후에 사용자 입력을 차단하지 않는다 - 호출은'setVisible (false)'까지 반환되지 않지만 EDT를 차단하지 않습니다 (이벤트는 여전히 처리됩니다). 'setVisible()'보다 먼저'execute()'를 호출하거나'doInBackground()'를 호출해야합니다. 연결된 닭/계란 질문을보십시오. 그것은 당신의 의심을 해결해야합니다. – predi