【问题标题】:Can someone please explain how to use threading in my script?有人可以解释如何在我的脚本中使用线程吗?
【发布时间】:2017-01-30 18:51:51
【问题描述】:

我已经用 python 玩了大约三个月了,几天前我需要做一些琐碎的任务(创建文件夹),我实际上做了一个脚本来做。

出于纯粹的完美主义,我想添加一个进度条,但是当我运行脚本时,它挂起,然后在完成后说完成。我希望看到进度条达到 100% 而不是挂起。我已经读过我需要使用 python 线程来执行此操作,但我真的很困惑如何实现它但也理解它。

我已经复制了理论上需要线程化的代码部分。如您所见,我正在使用 QT Designer 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)

【问题讨论】:

    标签: python multithreading for-loop pyqt


    【解决方案1】:

    通常最好将您的业务逻辑从 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)
    

    您在另一个线程中创建一个工作对象,该对象将执行此业务逻辑并使用信号将进度报告回主 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()
    

    然后将此工作器添加到您的 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,但这很多让我感到困惑。我不完全理解以下内容:for i, s in enumerate(shots):yield int((i + 1) / cnt * 100)@pyqtSlot(int)self.thread = QThread(self)self.worker = Worker(self)我写的很多东西都是从在线资源中收集的,我真的很想弄清楚这一切。
    • 第一个是 python generator (有很多关于如何创建和使用生成器的好文章,它们比我在这里给出的任何简短解释都要好)。 @pyqtSlot - Qt 使用信号和槽系统在某些事件期间作为其事件系统的一部分发送数据。从技术上讲,您不必总是使用pyqtSlot 将函数装饰为插槽,但为了跨线程通信,您可以这样做。
    猜你喜欢
    • 2011-01-08
    • 2014-10-13
    • 1970-01-01
    • 2016-06-25
    • 2011-12-26
    • 1970-01-01
    • 2017-09-02
    • 1970-01-01
    • 2011-03-08
    相关资源
    最近更新 更多