2017-08-09 3 views
1

Je voulais surveiller la progression de mon fichier copié de la source à la destination. J'ai utilisé le mot-clé synchronized, mais en quelque sorte, il ne fonctionne pas comme je l'attend, ma logique pourrait être erronée. Je serai heureux si vous m'aidez. Voici mon code.Affichage de la copie synchronisée avec jProgressBar

public class Download extends javax.swing.JFrame { 
    int val=0; 
    private Timer t; 
    private ActionListener a; 

/* Creates new form Download */ 
    public Download() { 
     initComponents(); 
     jProgressBar1.setValue(val); 
     a = new ActionListener() { 
      @Override 
      public void actionPerformed(ActionEvent ae) { 
      if (jProgressBar1.getValue() < val) 
       jProgressBar1.setValue(jProgressBar1.getValue()+1); 
      else 
       t.stop(); 
      }   
     }; 
    } 
    public synchronized void copy(String source,String url) 
    { 
     try {  
     val+=25; 
     t=new Timer(200,a); 
     t.start(); 
     FileInputStream fs = new FileInputStream(source); 
     FileOutputStream os = new FileOutputStream(url); 
     int b; 
     while ((b = fs.read()) != -1) { 
      os.write(b); 
     } 
     os.close(); 
     fs.close(); 
     } catch (Exception E) { 
     E.printStackTrace(); 
     }   
    } 

    private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {           
     JFileChooser chooser = new JFileChooser(); 
     chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 
     String url = null; 
     int returnValue = chooser.showDialog(null, "Select"); 
     if (returnValue == JFileChooser.APPROVE_OPTION) { 
     url = chooser.getSelectedFile().getPath(); 
     } else { 
     dispose(); 
     } 
     JOptionPane.showMessageDialog(this,"Wait for Completion"); 

     if(CB1.isSelected()==true) 
     { 
     File f = new File(getClass().getResource("/PCycle/Ele.pdf").getFile()); 
     String source= f.getAbsolutePath(); 
     copy(source,(url+"\\"+CB1.getText()+".pdf")); 
     } 
     if(CB2.isSelected()==true) 
     { 
     File f = new File(getClass().getResource("/PCycle/Mech.pdf").getFile()); 
     String source= f.getAbsolutePath(); 
     copy(source,(url+"\\"+CB2.getText()+".pdf")); 
     } 
     if(CB3.isSelected()==true) 
     { 
     File f = new File(getClass().getResource("/PCycle/Phy.pdf").getFile()); 
     String source= f.getAbsolutePath(); 
     copy(source,(url+"\\"+CB3.getText()+".pdf")); 
     } 
     if(CB4.isSelected()==true) 
     { 
     File f = new File(getClass().getResource("/PCycle/Civil.pdf").getFile()); 
     String source= f.getAbsolutePath(); 
     copy(source,(url+"\\"+CB4.getText()+".pdf")); 
     } 

     JOptionPane.showMessageDialog(this,"Completed"); 

     try { 
      jProgressBar1.setValue(100);     
      Thread.sleep(3000); 
     } catch (InterruptedException ex) { 
      Logger.getLogger(Download.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     System.exit(0); 
    } 
} 

Ici, j'essayé de mettre en œuvre une logique telle que, chaque fois que nous appelons la méthode « copie » il copie le fichier d'un endroit à l'autre et avant qu'il doit exécuter la méthode de la minuterie par lequel le progrès le jProgressBar est affiché. Mais malheureusement, même après avoir utilisé synchronized, il n'affiche pas la progression de chaque fichier.

+0

Vous pouvez utiliser [ProgressMonitorInputStream] (https://docs.oracle.com/javase/8/docs/api/javax/swing/ProgressMonitorInputStream.html), qui ouvre automatiquement un indicateur de progression lors de la lecture à partir d'un flux, si le processus prend une quantité de temps non négligeable. – AJNeufeld

Répondre

1

Le problème est que vous bloquez EDT (Swing Event Dispatching Thread).

Swing effectue tout le dessin lorsque l'EDT n'est pas occupé à répondre aux événements. Dans ce cas, jButton1ActionPerformed ne revient pas tant que tous les fichiers n'ont pas été copiés. Ainsi, bien qu'un Timer soit démarré lors de chaque appel copy(), les temporisateurs n'ont jamais la possibilité d'expirer, car jButton1ActionPerformed n'est jamais retourné.

Dans ce cas, vous souhaitez utiliser un SwingWorker pour copier les fichiers dans un fil d'arrière-plan.

  • Lorsque vous voulez commencer à copier les fichiers:
    • démarrer la minuterie dans le thread principal
    • créer et démarrer le SwingWorker.
    • ouvrir une boîte de dialogue de modèle pour bloquer d'autres actions de l'utilisateur (ou autrement désactiver l'interface utilisateur)
  • Comme la minuterie arrive à expiration, votre barre de progression avancera, et tirer.
  • Lorsque le SwingWorker est done() (qui est exécuté sur le HAE),
    • arrêter le chronomètre
    • rejeter la boîte de dialogue (ou réactiver l'interface utilisateur)

Remarque: Ne créez pas ou n'accédez pas aux éléments de l'interface utilisateur, ou créez/démarrez/arrêtez les minuteurs à partir du thread de travail en arrière-plan. Ces actions ne doivent être effectuées que sur l'EDT.


exemple rugueux, montrant la désactivation élément d'interface utilisateur, à partir SwingWorker, édition du travailleur pour montrer les progrès (quel fichier est le téléchargement), ce qui permet l'interface utilisateur lorsque le travailleur se termine.

La copie de fichier est faussée en utilisant un délai de 3 secondes.

package progress; 

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.util.List; 

import javax.swing.JButton; 
import javax.swing.JFrame; 
import javax.swing.JProgressBar; 
import javax.swing.SwingUtilities; 
import javax.swing.SwingWorker; 
import javax.swing.Timer; 

@SuppressWarnings("serial") 
public class Download extends JFrame { 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(Download::new); 
    } 

    private final JButton downloadBtn = new JButton("Start Download"); 
    private final JProgressBar progressBar = new JProgressBar(); 
    private final Timer timer = new Timer(200, this::timerTick); 

    Download() { 
     super("Download Example"); 
     setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     setSize(400, 300); 
     setLocationByPlatform(true); 

     downloadBtn.addActionListener(this::startDownload); 
     add(downloadBtn, BorderLayout.PAGE_START); 

     progressBar.setStringPainted(true); 
     add(progressBar, BorderLayout.PAGE_END); 

     setVisible(true); 
    } 

    private void startDownload(ActionEvent evt) { 
     downloadBtn.setEnabled(false); 
     timer.start(); 
     DownloadWorker worker = new DownloadWorker("File1", "FileB", "AnotherFile"); 
     worker.execute(); 
    } 

    private void timerTick(ActionEvent evt) { 
     progressBar.setValue(progressBar.getValue()+2); 
    } 

    private class DownloadWorker extends SwingWorker<Void, String> { 

     private final String[] files; 

     DownloadWorker(String ...files) { 
      this.files = files; 

      progressBar.setValue(0); 
     } 

     @Override 
     protected Void doInBackground() throws Exception { 
      for(String file : files) { 
       publish(file); 

       // Copy the file 
       Thread.sleep(3000); // Pretend copy takes a few seconds 
      } 
      return null; 
     } 

     @Override 
     protected void process(List<String> chunks) { 
      String file = chunks.get(chunks.size()-1); // Just last published filename 
      progressBar.setString("Downloading "+file + " ..."); 
     } 

     @Override 
     protected void done() { 
      progressBar.setString("Complete"); 
      progressBar.setValue(100); 
      timer.stop(); 
      downloadBtn.setEnabled(true); // Re-enable UI 
     } 
    } 
} 
+0

Merci monsieur. Il sera plus utile si vous pouvez fournir un exemple plus tôt. –

+0

Exemple ajouté. J'espère que vous pouvez l'adapter à vos besoins. La barre de progression avance simplement d'un montant fixe par tick, comme vous avez essayé de coder dans votre exemple de code problème. Idéalement, vous pouvez interroger le travailleur sur le nombre d'octets copiés, calculer un pourcentage réel de progression, etc. – AJNeufeld

+0

Merci monsieur, j'ai adapté les changements et cela m'a vraiment aidé. –