Foro de elhacker.net

Programación => Scripting => Mensaje iniciado por: erickcasita en 15 Abril 2019, 17:03 pm



Título: ¿Cómo conectar una barra de progreso utilizando QThread en PyQT5? [Python 3x]
Publicado por: erickcasita en 15 Abril 2019, 17:03 pm
He estado intentado pasar el proceso de descarga para los audios de Youtube en un hilo diferente utilizando la librería pafy. Con esta librería se puede utilizar un método llamado "mycb" donde es posible obtener los kbs descargados y los totales para establecer una barra de progreso. Aquí les muestro lo que intento hacer mediante la clase QThread

Código
  1.  
  2. from audio import *
  3. from PyQt5.QtWidgets import QApplication, QMainWindow, QDialog,QFileDialog, QMessageBox,QTableWidget,QTableWidgetItem
  4. from PyQt5.QtCore import QThread, pyqtSignal
  5. import getpass, glob, pafy
  6.  
  7. class DownloadAudio(QThread):
  8.    signal_recvd = pyqtSignal(int)
  9.    signal_total = pyqtSignal(int)
  10.    def download(self, ruta, url):
  11.        ruta = ruta
  12.        url = url
  13.        video = pafy.new(url)
  14.        title = video.title
  15.        duration = video.duration
  16.        dwn = video.getbestaudio()
  17.        dwn.download(filepath=ruta, callback=self.mycb, meta=True)
  18.  
  19.    def mycb(self,total, recvd, ratio, rate,eta): #Metodo de la libreria Pafy para saber los kbs recibidos y los totales (con este me apoyo para establecer la barra de progreso)
  20.        self.signal_total.emit(total)
  21.        self.signal_recvd.emit(recvd)
  22.  
  23.  
  24. class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
  25.    def __init__(self, *args, **kwargs):
  26.        QtWidgets.QMainWindow.__init__(self, *args, **kwargs)
  27.        self.setupUi(self)
  28.        self.setFixedSize(920,700)
  29.        self.txt_ruta.setText("/home/"+getpass.getuser()+"/Música")
  30.        self.tableWidget.setColumnWidth(0, 350)
  31.        self.tableWidget.setColumnWidth(1, 350)
  32.        self.btn_descargar.clicked.connect(self.download_audio)
  33.        self.btn_destino.clicked.connect(self.ruta)
  34.    def download_audio(self):
  35.        ruta = self.txt_ruta.text()
  36.        self.progressBar.setValue(0)
  37.        url = self.txt_url.text()
  38.        video = pafy.new(url)
  39.        title = video.title
  40.        duration = video.duration
  41.        self.tableWidget.setItem(0,0, QTableWidgetItem(title))
  42.        self.tableWidget.setItem(0,1, QTableWidgetItem(duration))
  43.        self.calc = DownloadAudio()
  44.        self.calc.download(ruta,url)
  45.        self.calc.signal_recvd.connect(self.progress)
  46.    def progress(self,value):
  47.        self.progressBar.setValue(value)
  48.  
  49.    def ruta(self):
  50.        path = os.path.normpath(QFileDialog.getExistingDirectory(self))
  51.        self.txt_ruta.setText(path)                
  52. if __name__ == '__main__':
  53.    app = QtWidgets.QApplication([])
  54.    window = MainWindow()
  55.    window.show()
  56.    app.exec_()
  57.  
  58.  


Con este código el proceso funciona aunque no correctamente ni mucho menos puedo establecer la barra de progreso.


Título: Re: ¿Cómo conectar una barra de progreso utilizando QThread en PyQT5? [Python 3x]
Publicado por: srWhiteSkull en 16 Abril 2019, 16:08 pm
No tengo tiempo para instalar Qt pero así por encima veo que defines una clase que hereda de un objeto QThread que por el nombre alude a un "hilo", un proceso que funciona en segundo plano.

https://www.riverbankcomputing.com/static/Docs/PyQt4/qthread.html

Viendo la documentación observo que QThread dispone de un método donde corre el hilo, el run. En teoría tal como indica la doc este me´todo indica que todo lo que metas ahí lo ejecuta en segundo plano. Por lo tanto necesitas incluir en esa clase que defines el método run que lo heredará de QThread.

Luego en el run debes poner un bucle condicional que termine cuando de alguna forma, tú sabrás, el fichero haya llegado al total o fuese descargado y entonces el bucle finalizaría. Dentro de ese mismo bucle es donde tendrías que actualizar la barra de progreso.

Una vez tengas todo eso, ya simplemente cuando instancies la clase DownloadAudio deberías invocar el método start. Y así debería funcionar, pero me imagino que deberías pasar la referencia de la barra de progreso.

Otra alternativa a ese diseño pienso que sería que ya que esa función mycb que defines te devuelve el tamaño, sería conveniente que el hilo lo ejecutara el componente de barra de progreso, y este mientras se ejecuta en segundo plano se vaya actualizando en cada vuelta del bucle en el run, consultando periódicamente esa función, mycb,y claro, que también tendrías que pasarle la referencia del DownloadAudio instanciado.


Título: Re: ¿Cómo conectar una barra de progreso utilizando QThread en PyQT5? [Python 3x]
Publicado por: erickcasita en 16 Abril 2019, 16:12 pm
Gracias por el algoritmo hermano, así mismo lo voy a intentar, saludos!