2017-03-26 2 views
0

Voici quelques exemples de code qui casse: Pourquoi les fonctions externes provoquent-elles le gel de la fenêtre PyQt5?

import sys 
import time 
from PyQt5.QtWidgets import (QApplication, QDialog, 
          QProgressBar) 

class Actions(QDialog): 
    def __init__(self): 
     super().__init__() 
     self.initUI() 

    def initUI(self): 
     self.progress = QProgressBar(self) 
     self.progress.setGeometry(0, 0, 300, 25) 
     self.show() 

     self.count = 0 

     while self.count < 100: 
      self.count += 1 
      time.sleep(1) # Example external function 
      self.progress.setValue(self.count) 

if __name__ == "__main__": 
    app = QApplication(sys.argv) 
    window = Actions() 
    sys.exit(app.exec_()) 

L'exécution de cette provoquera de geler et ne répond plus particulièrement dans les environnements Windows. Le remplacement de la fonction time.sleep par une fonction autre que PyQt5 donnera les mêmes résultats. D'après ce que je comprends cela a à voir avec la fonction n'étant pas appelée dans un thread séparé en utilisant QThread. J'ai utilisé this answer comme référence et suis venu avec une solution partielle.

import sys 
import time 

from PyQt5.QtCore import QThread 
from PyQt5.QtWidgets import (QApplication, QDialog, 
          QProgressBar) 

class External(QThread): 

    def run(self): 
     count = 0 

     while count < 100: 
      count += 1 
      print(count) 
      time.sleep(1) 

class Actions(QDialog): 
    def __init__(self): 
     super().__init__() 
     self.initUI() 

    def initUI(self): 
     self.progress = QProgressBar(self) 
     self.progress.setGeometry(0, 0, 300, 25) 
     self.show() 

if __name__ == "__main__": 
    app = QApplication(sys.argv) 
    window = Actions() 
    calc = External() 
    calc.finished.connect(app.exit) 
    calc.start() 
    sys.exit(app.exec_()) 

Cela se déroulera time.sleep en arrière-plan et de garder la fenêtre principale réactive. Mais, je ne sais pas comment mettre à jour les valeurs en utilisant self.progress.setValue car il n'est pas accessible dans la classe External. Si loin de ce que je sais, je dois utiliser des signaux pour accomplir ceci. La plupart des documents disponibles pour PyQt4 rendent la solution plus difficile.

Un autre problème que je suis confronté est de pouvoir démarrer le thread External à partir de la classe Actions.

Les réponses à ce problème serviront également de documentation précieuse pour PyQt5. Merci d'avance.

+1

Cette réponse montre comment câbler un filetage extérieur à une barre de progression par les signaux/slots. Je pense que c'est applicable à qt5 http://stackoverflow.com/questions/9682376/progress-bar-with-pyqt – tdelaney

Répondre

1

Vous devez utiliser les signaux pour mettre à jour les valeurs.

import sys 
import time 

from PyQt5.QtCore import QThread, pyqtSignal 
from PyQt5.QtWidgets import (QApplication, QDialog, 
          QProgressBar) 

class External(QThread): 
    countChanged = pyqtSignal(int) 
    def run(self): 
     count = 0 

     while count < 100: 
      count += 1 
      self.countChanged.emit(count) 
      print(count) 
      time.sleep(1) 

class Actions(QDialog): 
    def __init__(self): 
     super().__init__() 
     self.initUI() 

    def initUI(self): 
     self.progress = QProgressBar(self) 
     self.progress.setGeometry(0, 0, 300, 25) 
     self.show() 

    def onCountChanged(self, value): 
     self.progress.setValue(value) 

if __name__ == "__main__": 
    app = QApplication(sys.argv) 
    window = Actions() 
    calc = External() 
    calc.countChanged.connect(window.onCountChanged) 
    calc.start() 
    sys.exit(app.exec_()) 
0

Voici une version qui commence le fil à l'intérieur de la classe Actions et utilise un bouton:

import sys 
import time 

from PyQt5.QtCore import QThread, pyqtSignal 
from PyQt5.QtWidgets import (QApplication, QDialog, 
          QProgressBar, QPushButton) 

class External(QThread): 

    countChanged = pyqtSignal(int) 

    def run(self): 
     count = 0 

     while count < 100: 
      count += 1 
      time.sleep(1) 
      print(count) 
      self.countChanged.emit(count) 

class Actions(QDialog): 
    def __init__(self): 
     super().__init__() 
     self.initUI() 

    def initUI(self): 
     self.progress = QProgressBar(self) 
     self.progress.setGeometry(0, 0, 300, 25) 
     self.button = QPushButton('Start', self) 
     self.button.move(0, 30) 
     self.show() 

     self.button.clicked.connect(self.onButtonClick) 

    def onButtonClick(self): 
     self.calc = External() 
     self.calc.countChanged.connect(self.onCountChanged) 
     self.calc.start() 

    def onCountChanged(self, value): 
     self.progress.setValue(value) 

if __name__ == "__main__": 
    app = QApplication(sys.argv) 
    window = Actions() 
    sys.exit(app.exec_())