IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

PyQt Python Discussion :

faire apparaître un progressBar


Sujet :

PyQt Python

  1. #1
    Membre du Club
    Homme Profil pro
    débutant
    Inscrit en
    Février 2012
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : débutant
    Secteur : Alimentation

    Informations forums :
    Inscription : Février 2012
    Messages : 88
    Points : 56
    Points
    56
    Par défaut faire apparaître un progressBar
    Bonjour,
    Voici mon problème, je veux afficher une fenêtre composée d'un progressBar lors d'un téléchargement de fichier.
    Mais la fenêtre ne s'affiche qu'une fois le téléchargement terminé, donc pas grand intérêt.
    Voici un bout de code qui représente mon problème, j'ai simulé le téléchargement par une pause avec le "time"
    je fais apparaître le progressBar avant le time, il n’apparaît qu'une fois les 5 secondes passées ?
    Que se passe t'il ?
    si quelqu'un pouvait m'expliquer.
    Merci de votre retour

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
     
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    # Python 3.4
     
    import os, sys, time
    from PyQt5 import (QtWidgets, QtGui, QtCore)
     
     
    class Feuille( QtWidgets.QWidget) :
        def __init__(self, parent = None) :
            super().__init__( parent)
            self.setObjectName("Feuille")
            self.parent = parent
     
            self.bouton = QtWidgets.QPushButton("Lancer")
            self.bouton.setObjectName("Feuille bouton")
            self.bouton.clicked.connect(self.lancer)
     
            #progress bar
            self.progressBar = QtWidgets.QProgressBar()
            self.progressBar.setObjectName("Feuille progressBar")
     
            self.layout = QtWidgets.QVBoxLayout()
            self.layout.setObjectName("Feuille layout")
            self.layout.addWidget(self.bouton)
            self.setLayout(self.layout)
     
        def lancer(self):
            self.layout.addWidget(self.progressBar)
            self.progressBar.setTextVisible(False)
            self.progressBar.setMinimum(0)
            self.progressBar.setMaximum(0)
            self.progressBar.show()
            time.sleep(5)    # pause 5 seconds
     
     
    if __name__ == "__main__":
        app =  QtWidgets.QApplication (sys.argv)
        fp = Feuille()
        fp.show()
        sys.exit(app.exec_())

  2. #2
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Le problème de time.sleep(5), c'est que le programme attend 5 secondes comme demandé, sans rien faire!

    Le minimum pour afficher une chenille (à défaut d'une progression) dans la progressbar, c'est de lui "passer la main" de temps en temps pour que le graphique puisse se mette à jour.

    Voilà ton programme avec une modif minimale:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    #!/usr/bin/python
    # -*- coding: utf-8 -*-
    # Python 3.4
     
    import os, sys, time
    from PyQt5 import (QtWidgets, QtGui, QtCore)
     
     
    class Feuille( QtWidgets.QWidget) :
        def __init__(self, parent = None) :
            super().__init__( parent)
            self.setObjectName("Feuille")
            self.parent = parent
     
            self.bouton = QtWidgets.QPushButton("Lancer")
            self.bouton.setObjectName("Feuille bouton")
            self.bouton.clicked.connect(self.lancer)
     
            #progress bar
            self.progressBar = QtWidgets.QProgressBar()
            self.progressBar.setObjectName("Feuille progressBar")
     
            self.layout = QtWidgets.QVBoxLayout()
            self.layout.setObjectName("Feuille layout")
            self.layout.addWidget(self.bouton)
            self.setLayout(self.layout)
     
        def lancer(self):
            self.layout.addWidget(self.progressBar)
            self.progressBar.setTextVisible(False)
            self.progressBar.setMinimum(0)
            self.progressBar.setMaximum(0)
            self.progressBar.show()
     
            # partie modifiée
            #time.sleep(5)    # pause 5 seconds
            t = 0.0
            while t<5.0:
                t += 0.1
                time.sleep(0.1)
                QtCore.QCoreApplication.processEvents() # <= redonner la main au graphique pour mise à jour
            self.progressBar.hide()
     
    if __name__ == "__main__":
        app =  QtWidgets.QApplication (sys.argv)
        fp = Feuille()
        fp.show()
        sys.exit(app.exec_())
    Quand on a affaire à un processus qui ne renvoie jamais la main pendant son exécution (un calcul long par exemple), il faut le mettre dans un thread ou un processus.

    Pour faire une vraie progression, le "processus qui dure longtemps" est censé envoyer une indication de progression pour mettre à jour la barre. S'il s'agit d'un téléchargement par FTP avec ftplib, il faut utiliser le callback de retrbinary qui est appelé à chacun des blocs téléchargés. Il faut, bien sûr, avoir avant la taille du fichier à télécharger pour étalonner les 100% de la barre de progression.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  3. #3
    Membre du Club
    Homme Profil pro
    débutant
    Inscrit en
    Février 2012
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : débutant
    Secteur : Alimentation

    Informations forums :
    Inscription : Février 2012
    Messages : 88
    Points : 56
    Points
    56
    Par défaut
    Merci pour ta réponse qui correspond exactement à mon exemple.
    mais comme tu l'as deviné c'est pour télécharger un fichier par FTP.
    j'ai bien la taille du fichier, mais pour actualiser le progressbar je ne trouve pas comment avoir l’avancement du téléchargement ?
    merci de me donner une piste
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
     
    taille = ftp.size(fic_ftp)
    self.progressBar.setMinimum(0)
    self.progressBar.setMaximum(taille)
    with open(rep_fichier, 'wb') as f:
        ftp.retrbinary('RETR ' + fic_ftp, f.write)
        self.progressBar.setValue(?)
        QtCore.QCoreApplication.processEvents() # <= redonner la main au graphique pour mise à jour

  4. #4
    Expert éminent
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 462
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 462
    Points : 9 249
    Points
    9 249
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Je n'ai pas le temps aujourd'hui pour en faire plus, mais voilà l'idée:

    Dans l'instruction ftp.retrbinary('RETR ' + fic_ftp, f.write), il faut remplacer le f.write (=le callback) par une fonction qui reçoit comme argument le bloc binaire téléchargé, ajoute ce bloc au fichier local mais aussi envoie la mise à jour à la barre de progression sous forme de cumul des blocs / taille du fichier à télécharger.

    J'en ferai plus les jours prochains si tu n'y arrives pas.
    Un expert est une personne qui a fait toutes les erreurs qui peuvent être faites, dans un domaine étroit... (Niels Bohr)
    Mes recettes python: http://www.jpvweb.com

  5. #5
    Membre du Club
    Homme Profil pro
    débutant
    Inscrit en
    Février 2012
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : débutant
    Secteur : Alimentation

    Informations forums :
    Inscription : Février 2012
    Messages : 88
    Points : 56
    Points
    56
    Par défaut
    Merci Tyrtamos, j'ai vu des exemples avec un callback, je cherche.....

  6. #6
    Expert éminent

    Homme Profil pro
    Inscrit en
    Octobre 2008
    Messages
    4 300
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Octobre 2008
    Messages : 4 300
    Points : 6 780
    Points
    6 780
    Par défaut
    Salut,

    Supprime totalement le time.sleep qui ne sert à rien dans ton cas.

    Regarde ici: http://bazaar.launchpad.net/~vincent...ead:/loader.py
    Il s'agit d'un module destiné à downloader un fichier en supervisant le flux.

    Il s'agit d'urllib mais ce ne devrait pas être compliqué à adapter pour ftp.

    Je l'utilise avec ce code:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
     
    from loader import Loader
        ...
            self.loader = Loader()
            self.loader.loadingProgress.connect(self.display_progress)
            self.loader.loadingFinished.connect(self.on_downloading_finished)
        ...
        def initiate_loader(self, url, fname):
            self.file_size = self.loader.config_loader(url, fname)
            if isinstance(self.file_size, int):
                return True
     
            lgg.info('Loading error: %s' % self.file_size)
            return False
     
        def download(self):
            ...
            self.initiate_loader(stream, target):
            ...
            Thread(target=self.loader.download_mp4).start()
            ...etc

  7. #7
    Membre du Club
    Homme Profil pro
    débutant
    Inscrit en
    Février 2012
    Messages
    88
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : débutant
    Secteur : Alimentation

    Informations forums :
    Inscription : Février 2012
    Messages : 88
    Points : 56
    Points
    56
    Par défaut
    Voici les résultats de ma recherche, en suivant ta proposition Tyrtamos :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
     
    taille = ftp.size(fic_ftp)
    self.somme = 0
    self.progressBar.setMinimum(self.somme)
    self.progressBar.setMaximum(taille)
    with open(rep_fichier, 'wb') as f:
        def callback(data):
            f.write(data)
            self.somme += len(data)
            self.progressBar.setValue(self.somme)
            QtCore.QCoreApplication.processEvents() # <= redonner la main au graphique pour mise à jour
     
        ftp.retrbinary('RETR ' + fic_ftp, callback)
    Ça fonctionne plutôt bien, a voir si c'est la solution correcte ?

    Merci VinsS pour ta solution, c'est très gentil mais j'ai vraiment du mal à comprendre la procédure et je ne me sens pas de l'utiliser sans rien comprendre.

Discussions similaires

  1. Faire apparaître les entêtes d'un sous-état
    Par Le Pharaon dans le forum IHM
    Réponses: 3
    Dernier message: 10/07/2007, 12h52
  2. [Stratégie] Erreurs: faire apparaître une fenêtre
    Par seb.ch dans le forum AWT/Swing
    Réponses: 4
    Dernier message: 04/08/2005, 15h08
  3. [JTree] Faire apparaître visuellement le noeud sélectionné
    Par Bobsinglar dans le forum Composants
    Réponses: 3
    Dernier message: 03/06/2005, 16h26
  4. Faire apparaître un champ texte en cliquant sur un select
    Par yoyot dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 15/03/2005, 16h16

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo