问题描述
我正在尝试解决我的程序中的问题,这个问题是当我开始下载视频时,程序没有响应,我也看不到进度条移动,所以我尝试使用线程模块,但我无法解决问题所以我该如何解决问题
i'm trying to fix problem in my program and this problem is when i start download video the program not responding and i can't see also progress bar move so i tried used threading module but i can't fix problem so how i can fix problem
通过此代码,我可以下载视频并将数据发送到另一个函数,以检索我用来将其连接到进度条的信息
From this code I can download the video and send the data to another function to retrieve information that I use to connect it to the progress bar
def video(self): video_url = self.lineEdit_4.text() video_save = self.lineEdit_3.text() pafy_video = pafy.new(video_url) type_video = pafy_video.videostreams quality = self.comboBox.currentIndex() start_download = type_video[quality].download(filepath=video_save,callback=self.video_progressbar)
此代码是从视频功能接收信息以连接进度条
This code is received information from video function to connect with progress bar
def video_progressbar(self,total, recvd, ratio, rate, eta): self.progressBar_2.setValue(ratio * 100)
我用;python3.5 pyqt5 pafy
I use;python3.5 pyqt5 pafy
推荐答案
移动到另一个线程的一种方法是创建一个存在于另一个线程中的 QObject 并在插槽中执行该任务.并且该槽必须通过 QMetaObject::invokeMethod 或信号调用.
One way to move to another thread is to create a QObject that lives in another thread and execute that task in a slot. And that slot must be invoked through QMetaObject::invokeMethod or a signal.
import pafy from PyQt5 import QtCore, QtWidgets class MainWindow(QtWidgets.QMainWindow): def __init__(self, parent=None): super(MainWindow, self).__init__(parent) central_widget = QtWidgets.QWidget() self.setCentralWidget(central_widget) self.le_url = QtWidgets.QLineEdit("https://www.youtube.com/watch?v=bMt47wvK6u0") path = QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.DownloadLocation) self.le_output = QtWidgets.QLineEdit(path) self.btn_quality = QtWidgets.QPushButton("Get qualities") self.combo_quality = QtWidgets.QComboBox() self.btn_download = QtWidgets.QPushButton("Download") self.progressbar = QtWidgets.QProgressBar(maximum=100) self.downloader = DownLoader() thread = QtCore.QThread(self) thread.start() self.downloader.moveToThread(thread) self.btn_quality.clicked.connect(self.on_clicked_quality) self.btn_download.clicked.connect(self.download) self.btn_download.setDisabled(True) self.downloader.progressChanged.connect(self.progressbar.setValue) self.downloader.qualitiesChanged.connect(self.update_qualityes) self.downloader.finished.connect(self.on_finished) form_lay = QtWidgets.QFormLayout(central_widget) form_lay.addRow("Url: ", self.le_url) form_lay.addRow(self.btn_quality) form_lay.addRow("qualities: ", self.combo_quality) form_lay.addRow("Output: ", self.le_output) form_lay.addRow(self.btn_download) form_lay.addRow(self.progressbar) @QtCore.pyqtSlot() def on_finished(self): self.update_disables(False) @QtCore.pyqtSlot() def on_clicked_quality(self): video_url = self.le_url.text() QtCore.QMetaObject.invokeMethod(self.downloader, "get_qualities", QtCore.Qt.QueuedConnection, QtCore.Q_ARG(str, video_url)) @QtCore.pyqtSlot(list) def update_qualityes(self, types_of_video): for t in types_of_video: self.combo_quality.addItem(str(t), t) self.btn_download.setDisabled(False) @QtCore.pyqtSlot() def download(self): video_save = self.le_output.text() d = self.combo_quality.currentData() QtCore.QMetaObject.invokeMethod(self.downloader, "start_download", QtCore.Qt.QueuedConnection, QtCore.Q_ARG(object, d), QtCore.Q_ARG(str, video_save)) self.update_disables(True) def update_disables(self, state): self.combo_quality.setDisabled(state) self.btn_quality.setDisabled(state) self.le_output.setDisabled(state) self.le_url.setDisabled(state) self.btn_download.setDisabled(not state) class DownLoader(QtCore.QObject): progressChanged = QtCore.pyqtSignal(int) qualitiesChanged = QtCore.pyqtSignal(list) finished = QtCore.pyqtSignal() @QtCore.pyqtSlot(str) def get_qualities(self, video_url): pafy_video = pafy.new(video_url) types_of_video = pafy_video.allstreams # videostreams self.qualitiesChanged.emit(types_of_video) @QtCore.pyqtSlot(object, str) def start_download(self, d, filepath): d.download(filepath=filepath, callback=self.callback) def callback(self, total, recvd, ratio, rate, eta): val = int(ratio * 100) self.progressChanged.emit(val) if val == 100: self.finished.emit() if __name__ == '__main__': import sys app = QtWidgets.QApplication(sys.argv) w = MainWindow() w.resize(320, 480) w.show() sys.exit(app.exec_())
with threading.Thread:
import pafy import threading from PyQt5 import QtCore, QtWidgets class MainWindow(QtWidgets.QMainWindow): qualitiesChanged = QtCore.pyqtSignal(list) progressChanged = QtCore.pyqtSignal(int) finished = QtCore.pyqtSignal() def __init__(self, parent=None): super(MainWindow, self).__init__(parent) central_widget = QtWidgets.QWidget() self.setCentralWidget(central_widget) self.le_url = QtWidgets.QLineEdit("https://www.youtube.com/watch?v=bMt47wvK6u0") path = QtCore.QStandardPaths.writableLocation(QtCore.QStandardPaths.DownloadLocation) self.le_output = QtWidgets.QLineEdit(path) self.btn_quality = QtWidgets.QPushButton("Get qualities") self.combo_quality = QtWidgets.QComboBox() self.btn_download = QtWidgets.QPushButton("Download") self.progressbar = QtWidgets.QProgressBar(maximum=100) self.btn_quality.clicked.connect(self.on_clicked_quality) self.btn_download.clicked.connect(self.download) self.btn_download.setDisabled(True) self.progressChanged.connect(self.progressbar.setValue) self.qualitiesChanged.connect(self.update_qualityes) self.finished.connect(self.on_finished) form_lay = QtWidgets.QFormLayout(central_widget) form_lay.addRow("Url: ", self.le_url) form_lay.addRow(self.btn_quality) form_lay.addRow("qualities: ", self.combo_quality) form_lay.addRow("Output: ", self.le_output) form_lay.addRow(self.btn_download) form_lay.addRow(self.progressbar) @QtCore.pyqtSlot() def on_finished(self): self.update_disables(False) @QtCore.pyqtSlot() def on_clicked_quality(self): video_url = self.le_url.text() threading.Thread(target=self.get_qualities, args=(video_url,)).start() def get_qualities(self, video_url): pafy_video = pafy.new(video_url) types_of_video = pafy_video.allstreams # videostreams self.qualitiesChanged.emit(types_of_video) @QtCore.pyqtSlot(list) def update_qualityes(self, types_of_video): for t in types_of_video: self.combo_quality.addItem(str(t), t) self.btn_download.setDisabled(False) @QtCore.pyqtSlot() def download(self): video_save = self.le_output.text() d = self.combo_quality.currentData() threading.Thread(target=d.download, kwargs={'filepath': video_save, 'callback': self.callback}, daemon=True).start() def callback(self, total, recvd, ratio, rate, eta): print(ratio) val = int(ratio * 100) self.progressChanged.emit(val) if val == 100: self.finished.emit() def update_disables(self, state): self.combo_quality.setDisabled(state) self.btn_quality.setDisabled(state) self.le_output.setDisabled(state) self.le_url.setDisabled(state) self.btn_download.setDisabled(not state) if __name__ == '__main__': import sys app = QtWidgets.QApplication(sys.argv) w = MainWindow() w.resize(320, 480) w.show() sys.exit(app.exec_())