Как использовать многопоточность в функции, чтобы предотвратить зависание графического интерфейса?

Я делаю простой аудио-загрузчик из видео, но всякий раз, когда я нажимаю кнопку загрузки, графический интерфейс останавливается, пока загрузка не завершится. Я думал, что могу использовать потоки для таких вещей, но для этого есть почти сотни методов, но я не знаю, какой из них выбрать, и поэтому я так запутался, что хотел спросить вас.

Мой код здесь:

import sys
import threading
import pafy
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot

class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 button - pythonspot.com'
        self.left = 100
        self.top = 100
        self.width = 320
        self.height = 200
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        button = QPushButton('Coffee shop radio', self)
        button.move(10,10)
        button.clicked.connect(self.on_click)

        self.show()

    def on_click(self):
        url = "https://www.youtube.com/watch?v=IcvruhYk0po"
        video = pafy.new(url)

        bestaudio = video.getbestaudio()
        bestaudio.download()

if __name__ == '__main__':
    app = QApplication([])
    ex = App()
    sys.exit(app.exec_())

Немного изменил код, и он работает, спасибо всем.

import sys
import threading
import pafy
from time import sleep
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton, QLineEdit
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot

class App(QWidget):
    threads = []

    def __init__(self):
        super().__init__()
        self.title = 'YouDio'
        self.left = 100
        self.top = 100
        self.width = 280
        self.height = 90
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        button = QPushButton('DOWNLOAD', self)
        button.move(10,25)
        button.clicked.connect(self.on_click)

        self.line = QLineEdit(self)
        self.line.move(120,27)

        self.show()

    def on_click(self):
        self.t = threading.Thread(target=self.threaded)
        self.t.start()

    def threaded(self):
        url = self.line.text()
        video = pafy.new(url)

        bestaudio = video.getbestaudio()
        bestaudio.download()

if __name__ == '__main__':
    app = QApplication([])
    ex = App()
    sys.exit(app.exec_())

person ShooterLens Aim    schedule 15.04.2020    source источник
comment
Не следует перезаписывать существующие свойства класса, такие как width() и height(), так как вам может потребоваться легкий доступ к ним. Кроме того, показывать виджет внутри его __init__ обычно не очень хорошо, так как видимость должна быть установлена ​​вручную или в интерактивном режиме, после создания экземпляра.   -  person musicamante    schedule 16.04.2020


Ответы (1)


from threading import Thread
import sys
import threading
import pafy
from PyQt5.QtWidgets import QApplication, QWidget, QPushButton
from PyQt5.QtGui import QIcon
from PyQt5.QtCore import pyqtSlot


def download_me():
    url = "https://www.youtube.com/watch?v=IcvruhYk0po"
    video = pafy.new(url)

    bestaudio = video.getbestaudio()
    bestaudio.download()  

class App(QWidget):

    def __init__(self):
        super().__init__()
        self.title = 'PyQt5 button - pythonspot.com'
        self.left = 100
        self.top = 100
        self.width = 320
        self.height = 200
        self.initUI()

    def initUI(self):
        self.setWindowTitle(self.title)
        self.setGeometry(self.left, self.top, self.width, self.height)

        button = QPushButton('Coffee shop radio', self)
        button.move(10,10)
        button.clicked.connect(self.on_click)

        self.show()

    def on_click(self):
        t = Thread(target=download_me)
        t.daemon = True
        t.start()



if __name__ == '__main__':
    app = QApplication([])
    ex = App()
    sys.exit(app.exec_())

попробуй это!

На самом деле задача загрузки выполняется синхронно, поэтому ваш theard будет блокироваться до тех пор, пока задача загрузки не будет завершена ... вы должны поместить эту часть своего кода в поток демона.

Примечание. Я не знаю, можно ли смешивать поток Python с Qt, поэтому вам следует использовать хорошую Lib, но идея остается прежней.

person user1438644    schedule 15.04.2020
comment
Хотя теоретически ваш ответ может быть правильным, обычно не рекомендуется смешивать потоки Python с Qt, поскольку QThreads обычно считаются лучшим решением (в основном из-за всего предлагаемого ими механизма сигналов/слотов, но не только). - person musicamante; 16.04.2020
comment
#musicamante да, верно... я не программист Qt, поэтому... я отредактирую свой пост с замечанием, спасибо - person user1438644; 16.04.2020
comment
понял идею, спасибо! - person ShooterLens Aim; 16.04.2020
comment
@musicamante ИМХО, использование потоковой передачи или QThread можно использовать в обоих случаях, на самом деле QThread - это QObject, который обрабатывает собственный поток, который представляет собой многопоточность. Так что в целом оба варианта допустимы, очевидно, в зависимости от конкретного случая более удобен тот или иной метод. - person eyllanesc; 16.04.2020
comment
@eyllanesc Вы правы, я должен был сказать это по-другому, поскольку они концептуально одно и то же и технически ведут себя одинаково, но QThreads обычно является лучшим выбором из-за лучшей интеграции, которую они предлагают с Qt. - person musicamante; 16.04.2020