Python 有人能解释一下如何在我的脚本中使用线程吗?
我已经玩python大约三个月了,几天前我需要做一些琐碎的任务(文件夹创建),我实际上做了一个脚本来完成它 出于纯粹的完美主义,我想添加一个进度条,但当我运行脚本时,它会挂起,然后在完成后说完成。我希望看到进度条100%运行,不挂起。我已经读到,我需要使用python线程来实现这一点,但我真的很困惑如何实现它,但我也理解它 我已经复制了理论上需要执行的代码部分。如您所见,我使用的是QT设计器UI和进度条 此外,间距也不是问题。这是我第一次在Stack Overflow上发帖,所以如果我弄乱了这里的代码间距,请原谅 非常感谢你能为我解释这件事Python 有人能解释一下如何在我的脚本中使用线程吗?,python,multithreading,for-loop,pyqt,Python,Multithreading,For Loop,Pyqt,我已经玩python大约三个月了,几天前我需要做一些琐碎的任务(文件夹创建),我实际上做了一个脚本来完成它 出于纯粹的完美主义,我想添加一个进度条,但当我运行脚本时,它会挂起,然后在完成后说完成。我希望看到进度条100%运行,不挂起。我已经读到,我需要使用python线程来实现这一点,但我真的很困惑如何实现它,但我也理解它 我已经复制了理论上需要执行的代码部分。如您所见,我使用的是QT设计器UI和进度条 此外,间距也不是问题。这是我第一次在Stack Overflow上发帖,所以如果我弄乱了这里
class ShotCreator(QtGui.QDialog):
def __init__(self, *args):
ui = 'ShotCreator_UI.ui'
QtGui.QWidget.__init__(self, *args)
loadUi(ui, self)
self.show()
#Slots
self.connect(self.browseLocation_btn, QtCore.SIGNAL("clicked()"), self.openBrowse)
self.connect(self.create_btn, QtCore.SIGNAL("clicked()"), self.makeDir)
self.progressBar.setValue(0)
def makeDir(self):
#Get data
departments = self.queryValues()
shots = self.fullShotAmount()
proj = self.projName()
#Converting proj to string
proj = str(proj)
#Converting dirLoc to string
dirLoc = self.browseLocation.text()
dirLoc = str(dirLoc)
if dirLoc == "":
msgBox = QtGui.QMessageBox()
msgBox.setIcon(QMessageBox.Warning)
msgBox.setWindowTitle("Oops - Directory Location")
msgBox.setText("Please give a directory location")
msgBox.exec_()
#Creating shot numbers
shot = 0
for s in shots:
shot = shot + 5
sShot = ("00" + str(shot))
if not os.path.exists(sShot):
#Create shot folders
os.mkdir(sShot)
self.progressBar.setValue((int(s) / int(len(shots))* 100))
self.progressBar.setValue(100)
通常最好将您的业务逻辑移出GUI代码,并将其放在不依赖于Qt的单独模块中。这使得它更容易在另一个线程中执行它 对于需要进度反馈的函数,我通常将它们转换为生成器
from __future__ import division
def makeDir(dirloc, shots):
cnt = len(shots)
#Creating shot numbers
shot = 0
for i, s in enumerate(shots):
shot = shot + 5
sShot = ("00" + str(shot))
if not os.path.exists(sShot):
#Create shot folders
os.mkdir(sShot)
yield int((i + 1) / cnt * 100)
您可以在另一个线程中创建一个worker对象,该线程将执行此业务逻辑,并使用信号将进度报告回主GUI线程,以便进度条可以更新
class Worker(QObject):
progress_updated = pyqtSignal(int)
finished = pyqtSignal()
@pyqtSlot(object, object)
def makeDir(self, dirloc, shots):
for progress in makeDir(dirloc, shots):
self.progress_updated.emit(progress)
self.finished.emit()
然后将这个worker添加到GUI类并连接到信号
class ShotCreator(QtGui.QDialog):
start_makedirs = pyqtSignal(object, object)
def __init__(self, *args):
ui = 'ShotCreator_UI.ui'
QtGui.QWidget.__init__(self, *args)
loadUi(ui, self)
self.show()
#Slots
self.connect(self.browseLocation_btn, QtCore.SIGNAL("clicked()"), self.openBrowse)
self.connect(self.create_btn, QtCore.SIGNAL("clicked()"), self.makeDir)
self.progressBar.setValue(0)
self.thread = QThread(self)
self.worker = Worker(self)
self.worker.progress_updated.connect(self.update_progress)
self.worker.finished.connect(self.worker_finished)
self.start_makedirs.connect(self.worker.makeDir)
self.worker.moveToThread(self.thread)
self.thread.start()
def makeDir(self):
# gather information from gui
dirloc = ''
shots = []
...
self.start_makedirs.emit(dirloc, shots)
@pyqtSlot(int)
def update_progress(self, progress):
self.progressBar.setValue(progress)
@pyqtSlot()
def worker_finished(self):
self.progressBar.setValue(100)
通常最好将您的业务逻辑移出GUI代码,并将其放在不依赖于Qt的单独模块中。这使得它更容易在另一个线程中执行它 对于需要进度反馈的函数,我通常将它们转换为生成器
from __future__ import division
def makeDir(dirloc, shots):
cnt = len(shots)
#Creating shot numbers
shot = 0
for i, s in enumerate(shots):
shot = shot + 5
sShot = ("00" + str(shot))
if not os.path.exists(sShot):
#Create shot folders
os.mkdir(sShot)
yield int((i + 1) / cnt * 100)
您可以在另一个线程中创建一个worker对象,该线程将执行此业务逻辑,并使用信号将进度报告回主GUI线程,以便进度条可以更新
class Worker(QObject):
progress_updated = pyqtSignal(int)
finished = pyqtSignal()
@pyqtSlot(object, object)
def makeDir(self, dirloc, shots):
for progress in makeDir(dirloc, shots):
self.progress_updated.emit(progress)
self.finished.emit()
然后将这个worker添加到GUI类并连接到信号
class ShotCreator(QtGui.QDialog):
start_makedirs = pyqtSignal(object, object)
def __init__(self, *args):
ui = 'ShotCreator_UI.ui'
QtGui.QWidget.__init__(self, *args)
loadUi(ui, self)
self.show()
#Slots
self.connect(self.browseLocation_btn, QtCore.SIGNAL("clicked()"), self.openBrowse)
self.connect(self.create_btn, QtCore.SIGNAL("clicked()"), self.makeDir)
self.progressBar.setValue(0)
self.thread = QThread(self)
self.worker = Worker(self)
self.worker.progress_updated.connect(self.update_progress)
self.worker.finished.connect(self.worker_finished)
self.start_makedirs.connect(self.worker.makeDir)
self.worker.moveToThread(self.thread)
self.thread.start()
def makeDir(self):
# gather information from gui
dirloc = ''
shots = []
...
self.start_makedirs.emit(dirloc, shots)
@pyqtSlot(int)
def update_progress(self, progress):
self.progressBar.setValue(progress)
@pyqtSlot()
def worker_finished(self):
self.progressBar.setValue(100)
谢谢你的回复!我一直在看你的回复,因为你发布了它,也许我正在尝试做高级python的时候,我不完全了解一切,但很多这让我困惑。我不完全理解以下内容:
对于枚举中的I,s(shots):
产生int((I+1)/cnt*100)
@pyqtSlot(int)
self.thread=QThread(self)self.worker=worker(self)我写的很多东西都是从在线资源中收集的,我真的想弄明白。第一个是python生成器(有很多关于如何创建和使用生成器的好文章,比我在这里给出的任何简短解释都要好)@pyqtSlot
-Qt使用信号和插槽系统在特定事件期间发送数据,作为其事件系统的一部分。从技术上讲,您不必总是使用pyqtSlot
将函数装饰为插槽,但对于跨线程通信,您可以这样做。感谢您的回复!我一直在看你的回复,因为你发布了它,也许我正在尝试做高级python的时候,我不完全了解一切,但很多这让我困惑。我不完全理解以下内容:对于枚举中的I,s(shots):
产生int((I+1)/cnt*100)
@pyqtSlot(int)
self.thread=QThread(self)self.worker=worker(self)我写的很多东西都是从在线资源中收集的,我真的想弄明白。第一个是python生成器(有很多关于如何创建和使用生成器的好文章,比我在这里给出的任何简短解释都要好)@pyqtSlot
-Qt使用信号和插槽系统在特定事件期间发送数据,作为其事件系统的一部分。从技术上讲,您不必总是使用pyqtSlot
将函数修饰为插槽,但对于跨线程通信,您可以这样做。