当实现 QThread 时,要执行的任务应该在 run() 方法中完成,如果你想用线程提供的数据更新 GUI,则不应直接完成,而应该通过信号来完成,因为 GUI 只能在 main 中更新由此调用的线程为 GUI 线程。
class DownloadThread(QThread):
dataChanged = pyqtSignal(int, str, str, str)
Started, Paused, Resume, Stopped = range(4)
downloadError = pyqtSignal()
downloadFinished = pyqtSignal()
def __init__(self, parent=None):
QThread.__init__(self, parent)
self.state = DownloadThread.Stopped
self.params = {"url": "", "save_location": ""}
def setParams(self, params):
self.params = params
def setState(self, state):
self.state = state
def run(self):
obj = SmartDL(self.params["url"], progress_bar=False)
try:
obj.start(blocking=False)
while True:
self.dataChanged.emit(obj.get_progress() * 100,
str(obj.get_dl_size(human=True)),
str(obj.get_speed(human=True)),
str(obj.get_eta(human=True)))
time.sleep(0.2)
if self.state == DownloadThread.Paused:
obj.pause()
if self.state == DownloadThread.Resume:
obj.unpause()
self.state = DownloadThread.Started
if obj.isFinished():
break
if self.state == DownloadThread.Stopped:
obj.stop()
self.progressBar.setValue(0)
break
if obj.isSuccessful():
# os.rename(obj.get_dest(), save_location)
shutil.move(obj.get_dest(), self.params["save_location"])
if self.state == DownloadThread.Started:
self.downloadFinished.emit()
except:
self.downloadError.emit()
您应该避免使用全局变量,此外您还可以减少仅由一个变量一次更新的多个变量,因此我必须修改 GUI 代码。
class MainApp(QMainWindow, FORM_CLASS):
def __init__(self, parent=None):
# ...
self.Handle_Buttons()
self.download = DownloadThread(self)
self.download.dataChanged.connect(self.onDataChanged)
self.download.downloadError.connect(self.errorDownload)
self.download.downloadFinished.connect(self.successfulDownload)
def closeEvent(self, evnt):
# ...
def Handle_Ui(self):
# self.lineEdit.setFocus()
self.setFixedSize(861, 441)
def Handle_Buttons(self):
# ...
def onDataChanged(self, progress, downloaded, speed, remain):
self.progressBar.setValue(progress)
self.label_8.setText("Downloaded: " + downloaded)
self.label_38.setText("Speed: " + speed)
self.label_39.setText("Remaining Time: " + remain)
def Start(self):
directory = os.path.expanduser("~") + "\AppData\Local\Temp\pySmartDL"
if not os.path.exists(directory):
os.makedirs(directory)
params = {"url": self.lineEdit.text(),
"save_location": self.lineEdit_2.text()}
self.download.setParams(params)
self.download.setState(DownloadThread.Started)
self.download.start()
def Pause(self):
if self.pushButton_13.text() == "Pause Downloading":
self.download.setState(DownloadThread.Paused)
self.pushButton_13.setText("Resume Downloading")
elif self.pushButton_13.text() == "Resume Downloading":
self.download.setState(DownloadThread.Resume)
self.pushButton_13.setText("Pause Downloading")
def Stop(self):
self.download.setState(DownloadThread.Stopped)
self.progressBar.setValue(0)
def errorDownload(self):
QMessageBox.warning(self, "Download Error", "Download Failed")
def successfulDownload(self):
QMessageBox.information(self, "Download Completed", "Your Download is Completed")