2017-10-01 3 views
0

J'ai essayé de trouver un moyen d'exécuter et de mettre à jour plusieurs barres de progression en même temps, mais jusqu'à présent, je n'ai pas de chance. Je suppose que j'ai aussi besoin d'un système que/run/reset pour que cela fonctionne.PySide - mise à jour de plusieurs barres de progression

Des idées? J'ai joué avec QThreadPool et QRunnable, mais sans succès.


** Mise à jour: Code mis à jour basé sur this grand article. Il semble fonctionner, mais il y a un certain nombre de problèmes:

  • Je reçois un avertissement: QObject :: startTimer: minuteries ne peuvent pas être démarré à partir d'un autre thread

  • Dès que je change la fréquence de mise à jour dans la fonction execute_this_fn (comme la mise à jour sur 1,2,3 etc), tout se bloque. Je veux être en mesure de limiter le nombre de barres de progression à 3. Si je clique sur le bouton de démarrage plus de trois fois, elles doivent être suspendues.


from PySide.QtGui import * 
from PySide.QtCore import * 

import time 
import traceback, sys 

class WorkerSignals(QObject): 
    finished = Signal() 
    error = Signal(tuple) 
    result = Signal(object) 
    progress = Signal(int) 

class Worker(QRunnable): 
    def __init__(self, fn, bar, *args, **kwargs): 
     super(Worker, self).__init__() 
     self.fn = fn 
     self.bar = bar 
     self.args = args 
     self.kwargs = kwargs 
     self.signals = WorkerSignals() 

     # Add the callback to our kwargs 
     kwargs['progress_callback'] = self.signals.progress 

    @Slot() 
    def run(self): 
     # Retrieve args/kwargs here; and fire processing using them 
     try: 
      result = self.fn(self.bar, *self.args, **self.kwargs) 
     except: 
      traceback.print_exc() 
      exctype, value = sys.exc_info()[:2] 
      self.signals.error.emit((exctype, value, traceback.format_exc())) 
     else: 
      self.signals.result.emit(result) # Return the result of the processing 
     finally: 
      self.signals.finished.emit() # Done 

class MainWindow(QMainWindow): 

    def __init__(self, *args, **kwargs): 
     super(MainWindow, self).__init__(*args, **kwargs) 

     self.counter = 0 

     self.layout = QVBoxLayout() 

     b = QPushButton("Start thread") 
     b.pressed.connect(self.start_me) 

     self.layout.addWidget(b) 

     w = QWidget() 
     w.setLayout(self.layout) 

     self.setCentralWidget(w) 
     self.show() 

     self.threadpool = QThreadPool() 
     print("Multithreading with maximum %d threads" % self.threadpool.maxThreadCount()) 

    def progress_fn(self, n): 
     print("%d%% done" % n) 

    def execute_this_fn(self, bar, progress_callback): 
     for n in range(0, 5): 
      time.sleep(1) 
      calc = n*100/4 
      progress_callback.emit(calc) 
      bar.setValue(calc) 
     return "Done." 

    def print_output(self, s): 
     print(s) 

    def thread_complete(self): 
     print("THREAD COMPLETE!") 

    def start_me(self): 
     # Pass the function to execute 
     xx = self.progress_bar = QProgressBar() 
     self.layout.addWidget(xx) 
     worker = Worker(self.execute_this_fn, xx) # Any other args, kwargs are passed to the run function 
     worker.signals.result.connect(self.print_output) 
     worker.signals.finished.connect(self.thread_complete) 
     worker.signals.progress.connect(self.progress_fn) 

     # Execute 
     self.threadpool.start(worker) 


app = QApplication([]) 
window = MainWindow() 
app.exec_() 
+0

Qu'avez-vous essayé pour résoudre votre problème? Quel est le problème avec le code que vous affichez? – eyllanesc

+0

Vous utilisez le modèle de travail incorrect. Vous ne déplacez pas le Worker sur le thread avant de l'exécuter. Cela entraîne probablement la mise en file d'attente de la connexion signal/emplacement. – deets

+0

Ce code est juste un exemple pour une seule barre de progression. Je cherche un moyen d'avoir 5 barres de progression fonctionnant en même temps (avec des valeurs différentes). –

Répondre

0

il est arrivé à travailler en utilisant this comme base.

from PySide import QtCore 
from PySide import QtGui 

import sys 
import time 

import random 
class WorkerSignals(QtCore.QObject): 

    finished = QtCore.Signal() 
    error = QtCore.Signal(tuple) 
    result = QtCore.Signal(object) 
    progress = QtCore.Signal(list) 

class Worker(QtCore.QRunnable): 

    def __init__(self, num, bar): 
     super(Worker, self).__init__() 
     self.num = num 
     self.bar = bar 
     self.signals = WorkerSignals() 


    def run(self): 
     try: 

      for i in range(1, 101): 
       self.signals.progress.emit([self.bar, i]) 

       sleep_time = random.uniform(0.01, 0.3) 

       time.sleep(sleep_time) 

     except Exception as e: 
      print "Quit thread {0}".format(self.num) 
      return 

class Tasks(QtGui.QWidget): 
    def __init__(self): 
     super(Tasks, self).__init__() 


     self.pool = QtCore.QThreadPool.globalInstance() 
     self.pool.setMaxThreadCount(5) 

     self.layout = QtGui.QVBoxLayout() 
     self.btn = QtGui.QPushButton("start") 
     self.layout.addWidget(self.btn) 

     self.setLayout(self.layout) 

     self.btn.clicked.connect(self.start_me) 


    def start_me(self): 
     for task in range(10): 
      xx = QtGui.QProgressBar() 
      self.layout.addWidget(xx) 
      self.worker = Worker(task, xx) 
      self.worker.signals.progress.connect(self.setProgress) 
      self.pool.start(self.worker) 
     #self.pool.waitForDone() 

    def setProgress(self, l): 
     bar, num = l 
     bar.setValue(num) 
     #print l 

def main(): 
    app = QtGui.QApplication(sys.argv) 
    panel = Tasks() 
    panel.show() 
    app.exec_() 


if __name__ == '__main__': 
    main()