PyQt5 无法从 QThread stop/kill/exit
PyQt5 unable to stop/kill/exit from QThread
从 借用代码,我试图在它工作时找到 quit/kill Qthread 的方法,这里是我的代码,你可以在进程中退出主 window栏正在停止要复制的文件:
import os
import sys
import shutil
from PyQt5 import QtCore, QtWidgets
class myProgressDialog(QtWidgets.QProgressDialog):
def __init__(self, parent=None):
super(myProgressDialog, self).__init__(parent=parent)
def closeEvent(self, event):
"""Get the name of active window about to close
"""
print('cant close')
event.ignore()
class MainWindow(QtWidgets.QMainWindow):
startMoveFilesSignal = QtCore.pyqtSignal(str, str)
def __init__(self):
super(MainWindow, self).__init__()
# srcdir = "/media/zachlab/Windows/LinuxStorage/old/embryos"
# dstdir = "/media/zachlab/Windows/LinuxStorage/old/out"
srcdir = "in"
dstdir = "out"
self.le_src = QtWidgets.QLineEdit(srcdir)
self.le_dst = QtWidgets.QLineEdit(dstdir)
self.button = QtWidgets.QPushButton("Copy")
# self.button.clicked.connect(self.archiveEntry)
self.button.clicked.connect(self.archiveEntry2)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QFormLayout(central_widget)
lay.addRow("From: ", self.le_src)
lay.addRow("To: ", self.le_dst)
lay.addRow(self.button)
print('self,thread :', self.thread)
def archiveEntry2(self):
print('connected')
self.progressbar = myProgressDialog(self)
# RIMUOVO Cancel Button
self.progressbar.setCancelButton(None)
self.progressbar.hide()
self.thread = QtCore.QThread(self)
self.thread.start()
self.helper = MoveFileHelper()
self.startMoveFilesSignal.connect(self.helper.moveFilesWithProgress)
self.helper.progressChanged.connect(self.progressbar.setValue)
self.helper.finished.connect(self.on_finished)
self.helper.started.connect(self.progressbar.show)
self.helper.errorOccurred.connect(self.on_errorOcurred)
self.helper.moveToThread(self.thread)
self.archiveEntry()
## Questo funziona
def closeEvent(self, event):
"""Get the name of active window about to close
"""
print('killing thread')
try:
if self.thread.isRunning():
print('killing running thread', self.thread.isRunning())
# self.thread.terminate() ## ---------> error Qt has caught an exception thrown from an event handler.
self.thread.quit() ### funziona ma non in SPYDER
except Exception as Exceptionz:
print('Exception :', Exceptionz)
try:
print('killing running thread after quit :', self.thread.isRunning())
except:
print('quitted')
event.accept()
@QtCore.pyqtSlot()
def archiveEntry(self):
self.startMoveFilesSignal.emit(self.le_src.text(), self.le_dst.text())
self.progressbar.hide()
@QtCore.pyqtSlot()
def on_finished(self):
self.button.setText('Finished')
@QtCore.pyqtSlot(str)
def on_errorOcurred(self, msg):
QtWidgets.QMessageBox.critical(self, "Error Ocurred", msg)
class MoveFileHelper(QtCore.QObject):
progressChanged = QtCore.pyqtSignal(int)
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
errorOccurred = QtCore.pyqtSignal(str)
def calculateAndUpdate(self, done, total):
progress = int(round((done / float(total)) * 100))
self.progressChanged.emit(progress)
@staticmethod
def countFiles(directory):
count = 0
if os.path.isdir(directory):
for path, dirs, filenames in os.walk(directory):
count += len(filenames)
return count
@staticmethod
def makedirs(dest):
if not os.path.exists(dest):
os.makedirs(dest)
@QtCore.pyqtSlot(str, str)
def moveFilesWithProgress(self, src, dest):
numFiles = MoveFileHelper.countFiles(src)
# if os.path.exists(dest):
# self.errorOccurred.emit("Dest exist")
# return
if numFiles > 0:
self.started.emit()
MoveFileHelper.makedirs(dest)
numCopied = 0
for path, dirs, filenames in os.walk(src):
for directory in dirs:
destDir = path.replace(src, dest)
MoveFileHelper.makedirs(os.path.join(destDir, directory))
for sfile in filenames:
srcFile = os.path.join(path, sfile)
destFile = os.path.join(path.replace(src, dest), sfile)
shutil.copy(srcFile, destFile)
numCopied += 1
self.calculateAndUpdate(numCopied, numFiles)
for i in range(100000):
i = i*10
self.finished.emit()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = MainWindow()
ex.resize(640, ex.sizeHint().height())
ex.show()
sys.exit(app.exec_())
不确定这是否是杀死 Qthread 的正确方法,但似乎有效。
即使在停止 Qthread 后:self.thread.quit()
我停止复制文件
但是 self.thread.isRunning()
仍然 returns True
。
尝试拆分代码并添加另一个 window 时使用:
main.py
import os
import sys
import shutil
from PyQt5 import QtCore, QtWidgets
from mod007b_import import Windowz, MoveFileHelper, myProgressDialog
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
QtWidgets.QMainWindow.__init__(self)
self.layout = QtWidgets.QHBoxLayout()
self.lineEdit = QtWidgets.QLineEdit()
self.lineEdit.setText("Just to fill up the dialog")
self.layout.addWidget(self.lineEdit)
self.button = QtWidgets.QPushButton('pppppp')
self.layout.addWidget(self.button)
self.widget = QtWidgets.QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
self.setWindowTitle('Simple')
self.button.clicked.connect(self.newWindow)
self.listz = []
def newWindow(self):
print('newwindow')
self.pippo = Windowz() ########## RIVEDERE PARENT CHILD RELATIONSHIP
self.pippo.show()
# self.listz.append(self.pippo)
pw = self.pippo.parentWidget()
print('list : ', self.listz)
print(pw)
if pw is not None:
print('self :', self)
print('pw : ', pw, pw.layout)
print('pippo :', self.pippo)
# print(' central_widget :', central_widget, type( central_widget))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = MainWindow()
# ex.setWindowTitle('Simple**************')
ex.resize(640, ex.sizeHint().height())
ex.show()
sys.exit(app.exec_())
和
mod007b_import.py
import os
import sys
import shutil
from PyQt5 import QtCore, QtWidgets
class myProgressDialog(QtWidgets.QProgressDialog):
def __init__(self, parent=None):
super(myProgressDialog, self).__init__(parent=parent)
def closeEvent(self, event):
"""Get the name of active window about to close
"""
print('cant close')
event.ignore()
class Windowz(QtWidgets.QWidget):
# class Windowz(QtWidgets.QMainWindow):
startMoveFilesSignal = QtCore.pyqtSignal(str, str)
# def __init__(self,parent=None):
# # super(Windowz, self).__init__(parent=parent)
# super(Windowz, self).__init__(parent=parent)
def __init__(self):
# super(Windowz, self).__init__(parent=parent)
super().__init__()
# srcdir = "/media/zachlab/Windows/LinuxStorage/old/embryos"
# dstdir = "/media/zachlab/Windows/LinuxStorage/old/out"
srcdir = "in"
dstdir = "out"
self.le_src = QtWidgets.QLineEdit(srcdir)
self.le_dst = QtWidgets.QLineEdit(dstdir)
self.button = QtWidgets.QPushButton("Copy")
# self.button.clicked.connect(self.archiveEntry)
self.button.clicked.connect(self.archiveEntry2)
### spostati in Main
# central_widget2 = QtWidgets.QWidget()
# self.setCentralWidget(central_widget2)
# lay = QtWidgets.QFormLayout(central_widget2)
self.lay = QtWidgets.QFormLayout(self)
self.lay.addRow("From: ", self.le_src)
self.lay.addRow("To: ", self.le_dst)
self.lay.addRow(self.button)
print('self,thread :', self.thread)
# self.show()
def archiveEntry2(self):
print('connected')
self.progressbar = myProgressDialog(self)
# RIMUOVO Cancel Button
self.progressbar.setCancelButton(None)
self.progressbar.hide()
self.thread = QtCore.QThread(self)
self.thread.start()
self.helper = MoveFileHelper()
self.startMoveFilesSignal.connect(self.helper.moveFilesWithProgress)
self.helper.progressChanged.connect(self.progressbar.setValue)
self.helper.finished.connect(self.on_finished)
self.helper.started.connect(self.progressbar.show)
self.helper.errorOccurred.connect(self.on_errorOcurred)
self.helper.moveToThread(self.thread)
self.archiveEntry()
## Questo funziona
def closeEvent(self, event):
"""Get the name of active window about to close
"""
print('killing thread')
try:
if self.thread.isRunning():
print('killing running thread', self.thread.isRunning())
# self.thread.terminate() ## ---------> error Qt has caught an exception thrown from an event handler.
self.thread.quit() ### doesnt work
# self.progressbar.hide() ### hides the bar
# self.progressbar.close() ### doesnt work
try:
print('killing running thread after quit :', self.thread.isRunning())
except:
print('quitted')
except Exception as Exceptionz:
print('Exception :', Exceptionz)
event.accept()
@QtCore.pyqtSlot()
def archiveEntry(self):
self.startMoveFilesSignal.emit(self.le_src.text(), self.le_dst.text())
self.progressbar.hide()
@QtCore.pyqtSlot()
def on_finished(self):
self.button.setText('Finished')
@QtCore.pyqtSlot(str)
def on_errorOcurred(self, msg):
QtWidgets.QMessageBox.critical(self, "Error Ocurred", msg)
class MoveFileHelper(QtCore.QObject):
progressChanged = QtCore.pyqtSignal(int)
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
errorOccurred = QtCore.pyqtSignal(str)
def calculateAndUpdate(self, done, total):
progress = int(round((done / float(total)) * 100))
self.progressChanged.emit(progress)
@staticmethod
def countFiles(directory):
count = 0
if os.path.isdir(directory):
for path, dirs, filenames in os.walk(directory):
count += len(filenames)
return count
@staticmethod
def makedirs(dest):
if not os.path.exists(dest):
os.makedirs(dest)
@QtCore.pyqtSlot(str, str)
def moveFilesWithProgress(self, src, dest):
numFiles = MoveFileHelper.countFiles(src)
# if os.path.exists(dest):
# self.errorOccurred.emit("Dest exist")
# return
if numFiles > 0:
self.started.emit()
MoveFileHelper.makedirs(dest)
numCopied = 0
for path, dirs, filenames in os.walk(src):
for directory in dirs:
destDir = path.replace(src, dest)
MoveFileHelper.makedirs(os.path.join(destDir, directory))
for sfile in filenames:
srcFile = os.path.join(path, sfile)
destFile = os.path.join(path.replace(src, dest), sfile)
shutil.copy(srcFile, destFile)
numCopied += 1
self.calculateAndUpdate(numCopied, numFiles)
for i in range(100000):
i = i*10
self.finished.emit()
我得到第一个 window,按 'pppppp' 按钮它会转到第二个,与上面的单个文件脚本相同:按 'copy' 按钮启动copying/Qthread,但是当我关闭这个 window 即使 QThread 似乎停止了,进度条也不会消失,我可以隐藏进度条但无法关闭它,无论如何复制过程都会完成。
知道发生了什么吗?
PS
为了使脚本正常工作并具有可见的进度条,文件需要与 'in' 文件夹一起放在一个目录中,该文件夹具有足够的文件以使进程缓慢。
好的,感谢@musicamante 和 Stopping an infinite loop in a worker thread in PyQt5 the simplest way
我弄清楚了我的两个代码中的第一个有什么问题,这里是第一个 re-written 设置了标志以在 main window 关闭时终止复制循环,重要
评论与否:
# self.thread.quit()
# self.thread.wait()
in Mainwindow def closeEvent(self, event):
标志设置为 True (self.ctrl['break'] = True
) 后 QThread 运行 / not 运行 在脚本终止之前。对于标志,请参阅 解决方案 2:将可变变量作为控制变量传递 Stopping an infinite loop in a worker thread in PyQt5 the simplest way
import os
import sys
import shutil
from PyQt5 import QtCore, QtWidgets
class myProgressDialog(QtWidgets.QProgressDialog):
def __init__(self, parent=None):
super(myProgressDialog, self).__init__(parent=parent)
def closeEvent(self, event):
"""Get the name of active window about to close
"""
print('cant close')
event.ignore()
class MainWindow(QtWidgets.QMainWindow):
startMoveFilesSignal = QtCore.pyqtSignal(str, str)
def __init__(self):
super(MainWindow, self).__init__()
# srcdir = "/media/zachlab/Windows/LinuxStorage/old/embryos"
# dstdir = "/media/zachlab/Windows/LinuxStorage/old/out"
srcdir = "in"
dstdir = "out"
self.le_src = QtWidgets.QLineEdit(srcdir)
self.le_dst = QtWidgets.QLineEdit(dstdir)
self.button = QtWidgets.QPushButton("Copy")
# self.button.clicked.connect(self.archiveEntry)
self.button.clicked.connect(self.archiveEntry2)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QFormLayout(central_widget)
lay.addRow("From: ", self.le_src)
lay.addRow("To: ", self.le_dst)
lay.addRow(self.button)
self.ctrl = {'break': False} # dict with your control variable
print('id of ctrl in MainWindow:', id(self.ctrl))
def archiveEntry2(self):
print('connected')
self.progressbar = myProgressDialog(self)
self.progressbar.setWindowTitle('coopying files')
# RIMUOVO Cancel Button
self.progressbar.setCancelButton(None)
self.progressbar.hide()
self.thread = QtCore.QThread(self)
self.thread.start()
self.helper = MoveFileHelper(self.ctrl)
self.startMoveFilesSignal.connect(self.helper.moveFilesWithProgress)
self.helper.progressChanged.connect(self.progressbar.setValue)
self.helper.finished.connect(self.on_finished)
self.helper.started.connect(self.progressbar.show)
self.helper.errorOccurred.connect(self.on_errorOcurred)
self.helper.moveToThread(self.thread)
self.archiveEntry()
## Questo funziona
def closeEvent(self, event):
"""Get the name of active window about to close
"""
try:
print('killing thread')
print('self.thread.isRunning() before quit :', self.thread.isRunning())
if self.thread.isRunning():
print("quitted ----> self.ctrl['break'] = True")
self.ctrl['break'] = True
self.thread.quit()
self.thread.wait()
except Exception as Exceptionz:
print('Exception :', Exceptionz)
try:
print('self.thread.isRunning() after quit :', self.thread.isRunning())
except:
print('quitted')
# event.accept() # not needed implicit
# event.ignore()
@QtCore.pyqtSlot()
def archiveEntry(self):
self.startMoveFilesSignal.emit(self.le_src.text(), self.le_dst.text())
self.progressbar.hide()
@QtCore.pyqtSlot()
def on_finished(self):
print('on_finished self.ctrl inside worker : ', self.ctrl)
print('self.thread.isRunning() after quit on_finished :', self.thread.isRunning())
self.button.setText('Finished')
@QtCore.pyqtSlot(str)
def on_errorOcurred(self, msg):
QtWidgets.QMessageBox.critical(self, "Error Ocurred", msg)
class MoveFileHelper(QtCore.QObject):
progressChanged = QtCore.pyqtSignal(int)
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
errorOccurred = QtCore.pyqtSignal(str)
def __init__(self, ctrl):
super().__init__()
self.ctrl = ctrl # dict with your control var
print('self.ctrl inside worker MoveFileHelper : ', self.ctrl)
print('Entered run in worker thread')
print('id of ctrl in worker:', id(self.ctrl))
self.ctrl['break'] = False
def calculateAndUpdate(self, done, total):
progress = int(round((done / float(total)) * 100))
self.progressChanged.emit(progress)
@staticmethod
def countFiles(directory):
count = 0
if os.path.isdir(directory):
for path, dirs, filenames in os.walk(directory):
count += len(filenames)
return count
@staticmethod
def makedirs(dest):
if not os.path.exists(dest):
os.makedirs(dest)
@QtCore.pyqtSlot(str, str)
def moveFilesWithProgress(self, src, dest):
numFiles = MoveFileHelper.countFiles(src)
# if os.path.exists(dest):
# self.errorOccurred.emit("Dest exist")
# return
if numFiles > 0:
self.started.emit()
MoveFileHelper.makedirs(dest)
numCopied = 0
for path, dirs, filenames in os.walk(src):
for directory in dirs:
destDir = path.replace(src, dest)
MoveFileHelper.makedirs(os.path.join(destDir, directory))
for sfile in filenames:
if self.ctrl['break'] : # == True : is implicit
self.finished.emit()
return
else:
srcFile = os.path.join(path, sfile)
destFile = os.path.join(path.replace(src, dest), sfile)
shutil.copy(srcFile, destFile)
numCopied += 1
self.calculateAndUpdate(numCopied, numFiles)
for i in range(100000):
i = i*10
self.finished.emit()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = MainWindow()
ex.resize(640, ex.sizeHint().height())
ex.show()
sys.exit(app.exec_())
从
import os
import sys
import shutil
from PyQt5 import QtCore, QtWidgets
class myProgressDialog(QtWidgets.QProgressDialog):
def __init__(self, parent=None):
super(myProgressDialog, self).__init__(parent=parent)
def closeEvent(self, event):
"""Get the name of active window about to close
"""
print('cant close')
event.ignore()
class MainWindow(QtWidgets.QMainWindow):
startMoveFilesSignal = QtCore.pyqtSignal(str, str)
def __init__(self):
super(MainWindow, self).__init__()
# srcdir = "/media/zachlab/Windows/LinuxStorage/old/embryos"
# dstdir = "/media/zachlab/Windows/LinuxStorage/old/out"
srcdir = "in"
dstdir = "out"
self.le_src = QtWidgets.QLineEdit(srcdir)
self.le_dst = QtWidgets.QLineEdit(dstdir)
self.button = QtWidgets.QPushButton("Copy")
# self.button.clicked.connect(self.archiveEntry)
self.button.clicked.connect(self.archiveEntry2)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QFormLayout(central_widget)
lay.addRow("From: ", self.le_src)
lay.addRow("To: ", self.le_dst)
lay.addRow(self.button)
print('self,thread :', self.thread)
def archiveEntry2(self):
print('connected')
self.progressbar = myProgressDialog(self)
# RIMUOVO Cancel Button
self.progressbar.setCancelButton(None)
self.progressbar.hide()
self.thread = QtCore.QThread(self)
self.thread.start()
self.helper = MoveFileHelper()
self.startMoveFilesSignal.connect(self.helper.moveFilesWithProgress)
self.helper.progressChanged.connect(self.progressbar.setValue)
self.helper.finished.connect(self.on_finished)
self.helper.started.connect(self.progressbar.show)
self.helper.errorOccurred.connect(self.on_errorOcurred)
self.helper.moveToThread(self.thread)
self.archiveEntry()
## Questo funziona
def closeEvent(self, event):
"""Get the name of active window about to close
"""
print('killing thread')
try:
if self.thread.isRunning():
print('killing running thread', self.thread.isRunning())
# self.thread.terminate() ## ---------> error Qt has caught an exception thrown from an event handler.
self.thread.quit() ### funziona ma non in SPYDER
except Exception as Exceptionz:
print('Exception :', Exceptionz)
try:
print('killing running thread after quit :', self.thread.isRunning())
except:
print('quitted')
event.accept()
@QtCore.pyqtSlot()
def archiveEntry(self):
self.startMoveFilesSignal.emit(self.le_src.text(), self.le_dst.text())
self.progressbar.hide()
@QtCore.pyqtSlot()
def on_finished(self):
self.button.setText('Finished')
@QtCore.pyqtSlot(str)
def on_errorOcurred(self, msg):
QtWidgets.QMessageBox.critical(self, "Error Ocurred", msg)
class MoveFileHelper(QtCore.QObject):
progressChanged = QtCore.pyqtSignal(int)
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
errorOccurred = QtCore.pyqtSignal(str)
def calculateAndUpdate(self, done, total):
progress = int(round((done / float(total)) * 100))
self.progressChanged.emit(progress)
@staticmethod
def countFiles(directory):
count = 0
if os.path.isdir(directory):
for path, dirs, filenames in os.walk(directory):
count += len(filenames)
return count
@staticmethod
def makedirs(dest):
if not os.path.exists(dest):
os.makedirs(dest)
@QtCore.pyqtSlot(str, str)
def moveFilesWithProgress(self, src, dest):
numFiles = MoveFileHelper.countFiles(src)
# if os.path.exists(dest):
# self.errorOccurred.emit("Dest exist")
# return
if numFiles > 0:
self.started.emit()
MoveFileHelper.makedirs(dest)
numCopied = 0
for path, dirs, filenames in os.walk(src):
for directory in dirs:
destDir = path.replace(src, dest)
MoveFileHelper.makedirs(os.path.join(destDir, directory))
for sfile in filenames:
srcFile = os.path.join(path, sfile)
destFile = os.path.join(path.replace(src, dest), sfile)
shutil.copy(srcFile, destFile)
numCopied += 1
self.calculateAndUpdate(numCopied, numFiles)
for i in range(100000):
i = i*10
self.finished.emit()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = MainWindow()
ex.resize(640, ex.sizeHint().height())
ex.show()
sys.exit(app.exec_())
不确定这是否是杀死 Qthread 的正确方法,但似乎有效。
即使在停止 Qthread 后:self.thread.quit()
我停止复制文件
但是 self.thread.isRunning()
仍然 returns True
。
尝试拆分代码并添加另一个 window 时使用:
main.py
import os
import sys
import shutil
from PyQt5 import QtCore, QtWidgets
from mod007b_import import Windowz, MoveFileHelper, myProgressDialog
class MainWindow(QtWidgets.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
QtWidgets.QMainWindow.__init__(self)
self.layout = QtWidgets.QHBoxLayout()
self.lineEdit = QtWidgets.QLineEdit()
self.lineEdit.setText("Just to fill up the dialog")
self.layout.addWidget(self.lineEdit)
self.button = QtWidgets.QPushButton('pppppp')
self.layout.addWidget(self.button)
self.widget = QtWidgets.QWidget()
self.widget.setLayout(self.layout)
self.setCentralWidget(self.widget)
self.setWindowTitle('Simple')
self.button.clicked.connect(self.newWindow)
self.listz = []
def newWindow(self):
print('newwindow')
self.pippo = Windowz() ########## RIVEDERE PARENT CHILD RELATIONSHIP
self.pippo.show()
# self.listz.append(self.pippo)
pw = self.pippo.parentWidget()
print('list : ', self.listz)
print(pw)
if pw is not None:
print('self :', self)
print('pw : ', pw, pw.layout)
print('pippo :', self.pippo)
# print(' central_widget :', central_widget, type( central_widget))
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = MainWindow()
# ex.setWindowTitle('Simple**************')
ex.resize(640, ex.sizeHint().height())
ex.show()
sys.exit(app.exec_())
和
mod007b_import.py
import os
import sys
import shutil
from PyQt5 import QtCore, QtWidgets
class myProgressDialog(QtWidgets.QProgressDialog):
def __init__(self, parent=None):
super(myProgressDialog, self).__init__(parent=parent)
def closeEvent(self, event):
"""Get the name of active window about to close
"""
print('cant close')
event.ignore()
class Windowz(QtWidgets.QWidget):
# class Windowz(QtWidgets.QMainWindow):
startMoveFilesSignal = QtCore.pyqtSignal(str, str)
# def __init__(self,parent=None):
# # super(Windowz, self).__init__(parent=parent)
# super(Windowz, self).__init__(parent=parent)
def __init__(self):
# super(Windowz, self).__init__(parent=parent)
super().__init__()
# srcdir = "/media/zachlab/Windows/LinuxStorage/old/embryos"
# dstdir = "/media/zachlab/Windows/LinuxStorage/old/out"
srcdir = "in"
dstdir = "out"
self.le_src = QtWidgets.QLineEdit(srcdir)
self.le_dst = QtWidgets.QLineEdit(dstdir)
self.button = QtWidgets.QPushButton("Copy")
# self.button.clicked.connect(self.archiveEntry)
self.button.clicked.connect(self.archiveEntry2)
### spostati in Main
# central_widget2 = QtWidgets.QWidget()
# self.setCentralWidget(central_widget2)
# lay = QtWidgets.QFormLayout(central_widget2)
self.lay = QtWidgets.QFormLayout(self)
self.lay.addRow("From: ", self.le_src)
self.lay.addRow("To: ", self.le_dst)
self.lay.addRow(self.button)
print('self,thread :', self.thread)
# self.show()
def archiveEntry2(self):
print('connected')
self.progressbar = myProgressDialog(self)
# RIMUOVO Cancel Button
self.progressbar.setCancelButton(None)
self.progressbar.hide()
self.thread = QtCore.QThread(self)
self.thread.start()
self.helper = MoveFileHelper()
self.startMoveFilesSignal.connect(self.helper.moveFilesWithProgress)
self.helper.progressChanged.connect(self.progressbar.setValue)
self.helper.finished.connect(self.on_finished)
self.helper.started.connect(self.progressbar.show)
self.helper.errorOccurred.connect(self.on_errorOcurred)
self.helper.moveToThread(self.thread)
self.archiveEntry()
## Questo funziona
def closeEvent(self, event):
"""Get the name of active window about to close
"""
print('killing thread')
try:
if self.thread.isRunning():
print('killing running thread', self.thread.isRunning())
# self.thread.terminate() ## ---------> error Qt has caught an exception thrown from an event handler.
self.thread.quit() ### doesnt work
# self.progressbar.hide() ### hides the bar
# self.progressbar.close() ### doesnt work
try:
print('killing running thread after quit :', self.thread.isRunning())
except:
print('quitted')
except Exception as Exceptionz:
print('Exception :', Exceptionz)
event.accept()
@QtCore.pyqtSlot()
def archiveEntry(self):
self.startMoveFilesSignal.emit(self.le_src.text(), self.le_dst.text())
self.progressbar.hide()
@QtCore.pyqtSlot()
def on_finished(self):
self.button.setText('Finished')
@QtCore.pyqtSlot(str)
def on_errorOcurred(self, msg):
QtWidgets.QMessageBox.critical(self, "Error Ocurred", msg)
class MoveFileHelper(QtCore.QObject):
progressChanged = QtCore.pyqtSignal(int)
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
errorOccurred = QtCore.pyqtSignal(str)
def calculateAndUpdate(self, done, total):
progress = int(round((done / float(total)) * 100))
self.progressChanged.emit(progress)
@staticmethod
def countFiles(directory):
count = 0
if os.path.isdir(directory):
for path, dirs, filenames in os.walk(directory):
count += len(filenames)
return count
@staticmethod
def makedirs(dest):
if not os.path.exists(dest):
os.makedirs(dest)
@QtCore.pyqtSlot(str, str)
def moveFilesWithProgress(self, src, dest):
numFiles = MoveFileHelper.countFiles(src)
# if os.path.exists(dest):
# self.errorOccurred.emit("Dest exist")
# return
if numFiles > 0:
self.started.emit()
MoveFileHelper.makedirs(dest)
numCopied = 0
for path, dirs, filenames in os.walk(src):
for directory in dirs:
destDir = path.replace(src, dest)
MoveFileHelper.makedirs(os.path.join(destDir, directory))
for sfile in filenames:
srcFile = os.path.join(path, sfile)
destFile = os.path.join(path.replace(src, dest), sfile)
shutil.copy(srcFile, destFile)
numCopied += 1
self.calculateAndUpdate(numCopied, numFiles)
for i in range(100000):
i = i*10
self.finished.emit()
我得到第一个 window,按 'pppppp' 按钮它会转到第二个,与上面的单个文件脚本相同:按 'copy' 按钮启动copying/Qthread,但是当我关闭这个 window 即使 QThread 似乎停止了,进度条也不会消失,我可以隐藏进度条但无法关闭它,无论如何复制过程都会完成。
知道发生了什么吗?
PS
为了使脚本正常工作并具有可见的进度条,文件需要与 'in' 文件夹一起放在一个目录中,该文件夹具有足够的文件以使进程缓慢。
好的,感谢@musicamante 和 Stopping an infinite loop in a worker thread in PyQt5 the simplest way
我弄清楚了我的两个代码中的第一个有什么问题,这里是第一个 re-written 设置了标志以在 main window 关闭时终止复制循环,重要
评论与否:
# self.thread.quit()
# self.thread.wait()
in Mainwindow def closeEvent(self, event):
标志设置为 True (self.ctrl['break'] = True
) 后 QThread 运行 / not 运行 在脚本终止之前。对于标志,请参阅 解决方案 2:将可变变量作为控制变量传递 Stopping an infinite loop in a worker thread in PyQt5 the simplest way
import os
import sys
import shutil
from PyQt5 import QtCore, QtWidgets
class myProgressDialog(QtWidgets.QProgressDialog):
def __init__(self, parent=None):
super(myProgressDialog, self).__init__(parent=parent)
def closeEvent(self, event):
"""Get the name of active window about to close
"""
print('cant close')
event.ignore()
class MainWindow(QtWidgets.QMainWindow):
startMoveFilesSignal = QtCore.pyqtSignal(str, str)
def __init__(self):
super(MainWindow, self).__init__()
# srcdir = "/media/zachlab/Windows/LinuxStorage/old/embryos"
# dstdir = "/media/zachlab/Windows/LinuxStorage/old/out"
srcdir = "in"
dstdir = "out"
self.le_src = QtWidgets.QLineEdit(srcdir)
self.le_dst = QtWidgets.QLineEdit(dstdir)
self.button = QtWidgets.QPushButton("Copy")
# self.button.clicked.connect(self.archiveEntry)
self.button.clicked.connect(self.archiveEntry2)
central_widget = QtWidgets.QWidget()
self.setCentralWidget(central_widget)
lay = QtWidgets.QFormLayout(central_widget)
lay.addRow("From: ", self.le_src)
lay.addRow("To: ", self.le_dst)
lay.addRow(self.button)
self.ctrl = {'break': False} # dict with your control variable
print('id of ctrl in MainWindow:', id(self.ctrl))
def archiveEntry2(self):
print('connected')
self.progressbar = myProgressDialog(self)
self.progressbar.setWindowTitle('coopying files')
# RIMUOVO Cancel Button
self.progressbar.setCancelButton(None)
self.progressbar.hide()
self.thread = QtCore.QThread(self)
self.thread.start()
self.helper = MoveFileHelper(self.ctrl)
self.startMoveFilesSignal.connect(self.helper.moveFilesWithProgress)
self.helper.progressChanged.connect(self.progressbar.setValue)
self.helper.finished.connect(self.on_finished)
self.helper.started.connect(self.progressbar.show)
self.helper.errorOccurred.connect(self.on_errorOcurred)
self.helper.moveToThread(self.thread)
self.archiveEntry()
## Questo funziona
def closeEvent(self, event):
"""Get the name of active window about to close
"""
try:
print('killing thread')
print('self.thread.isRunning() before quit :', self.thread.isRunning())
if self.thread.isRunning():
print("quitted ----> self.ctrl['break'] = True")
self.ctrl['break'] = True
self.thread.quit()
self.thread.wait()
except Exception as Exceptionz:
print('Exception :', Exceptionz)
try:
print('self.thread.isRunning() after quit :', self.thread.isRunning())
except:
print('quitted')
# event.accept() # not needed implicit
# event.ignore()
@QtCore.pyqtSlot()
def archiveEntry(self):
self.startMoveFilesSignal.emit(self.le_src.text(), self.le_dst.text())
self.progressbar.hide()
@QtCore.pyqtSlot()
def on_finished(self):
print('on_finished self.ctrl inside worker : ', self.ctrl)
print('self.thread.isRunning() after quit on_finished :', self.thread.isRunning())
self.button.setText('Finished')
@QtCore.pyqtSlot(str)
def on_errorOcurred(self, msg):
QtWidgets.QMessageBox.critical(self, "Error Ocurred", msg)
class MoveFileHelper(QtCore.QObject):
progressChanged = QtCore.pyqtSignal(int)
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
errorOccurred = QtCore.pyqtSignal(str)
def __init__(self, ctrl):
super().__init__()
self.ctrl = ctrl # dict with your control var
print('self.ctrl inside worker MoveFileHelper : ', self.ctrl)
print('Entered run in worker thread')
print('id of ctrl in worker:', id(self.ctrl))
self.ctrl['break'] = False
def calculateAndUpdate(self, done, total):
progress = int(round((done / float(total)) * 100))
self.progressChanged.emit(progress)
@staticmethod
def countFiles(directory):
count = 0
if os.path.isdir(directory):
for path, dirs, filenames in os.walk(directory):
count += len(filenames)
return count
@staticmethod
def makedirs(dest):
if not os.path.exists(dest):
os.makedirs(dest)
@QtCore.pyqtSlot(str, str)
def moveFilesWithProgress(self, src, dest):
numFiles = MoveFileHelper.countFiles(src)
# if os.path.exists(dest):
# self.errorOccurred.emit("Dest exist")
# return
if numFiles > 0:
self.started.emit()
MoveFileHelper.makedirs(dest)
numCopied = 0
for path, dirs, filenames in os.walk(src):
for directory in dirs:
destDir = path.replace(src, dest)
MoveFileHelper.makedirs(os.path.join(destDir, directory))
for sfile in filenames:
if self.ctrl['break'] : # == True : is implicit
self.finished.emit()
return
else:
srcFile = os.path.join(path, sfile)
destFile = os.path.join(path.replace(src, dest), sfile)
shutil.copy(srcFile, destFile)
numCopied += 1
self.calculateAndUpdate(numCopied, numFiles)
for i in range(100000):
i = i*10
self.finished.emit()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
ex = MainWindow()
ex.resize(640, ex.sizeHint().height())
ex.show()
sys.exit(app.exec_())