【问题标题】:Python PyQT: How to call a GUI function from a worker thread?Python PyQT:如何从工作线程调用 GUI 函数?
【发布时间】:2014-07-18 08:03:42
【问题描述】:

我有一个 pyqt gui 并调用一个长进程 (ffmpeg),我把它放在一个单独的线程上以不阻塞 gui。然后,我想在更长的命令列表中的一个命令完成时更新进度条。问题是,我无法从工作线程中调用 gui 线程中的函数。所以我让在工作线程中运行一个ticker,但是当我用while循环更新进度条并读取ticker值时,gui再次被阻塞。我该如何解决这个问题。我目前使用的是 python 线程而不是 Qthread。 感谢您的帮助!

import threading, pexpect

self.cmd_list = ['ffmpeg -i file outfile','and so on']

self.stop_proc = False
self.executeCMD()

def spawn_ffmpeg_cmd(self):
    for cmd in self.cmd_list:
        if self.stop_proc == False:
            thread = pexpect.spawn(cmd)
            print "\nstarted: %s" % cmd
            cpl = thread.compile_pattern_list([pexpect.EOF,"frame= *\d+ fps=*\d+",'(.+)'])

            while True:
                i = thread.expect_list(cpl, timeout=None)
                if i == 0: # EOF
                    print "the sub process exited"
                    self.pgticker += 1
                    break
                elif i == 1:
                    frame_number_fps = thread.match.group(0)
                    print frame_number_fps
                    thread.close
                elif i == 2:
                    pass
    self.startButton.setEnabled(True)


def executeCMD(self):
    self.startButton.setEnabled(False)
    self.pgticker = 0
    threading.Thread(target=self.spawn_ffmpeg_cmd, name="_proc").start()


def stopprocess(self):
    self.stop_proc = True
    self.cmd_list = []
    os.system('pkill ffmpeg') 
    self.pgticker = len(self.cmd_list)
    self.startButton.setEnabled(True)


def updateProgress(self):  
    pgfactor = 100 / len(self.cmd_list)
    progress = 0.0
    progress = pgfactor*int(self.pgticker)
    self.progressBar.setProperty("value", progress)

【问题讨论】:

    标签: python multithreading user-interface ffmpeg


    【解决方案1】:

    简而言之:移动到QThread 并使用Qt 的信号和槽,它们是线程间通信的首选方式。

    此答案提供了一些示例: https://stackoverflow.com/a/6789205/2319400

    在您的情况下,使用上面的“SomeObject”版本可能如下所示:

    class Worker(QtCore.QObject):
    
        madeProgress = QtCore.pyqtSignal([int])
        finished = QtCore.pyqtSignal()
    
        def __init__(self, cmdlist):
            self.cmdlist = cmdlist
    
        def run(self):
            for icmd, cmd in enumerate(self.cmdlist):
                # execute your work
                # processCommand(cmd)
    
                # signal that we've made progress
                self.madeProgress.emit(icmd)
    
            # emit the finished signal - we're done
            self.finished.emit()
    

    然后将此工作器移动到您创建的QThread 实例。 按照链接答案中的模式,您可以连接 madeProgress 信号 到进度条的setValue 槽:

    workerThread = QThread()
    workerObject = Worker(cmdlist)
    workerObject.moveToThread(workerThread)
    workerThread.started.connect(workerObject.run)
    workerObject.finished.connect(workerThread.quit)
    
    # create a progressbar with min/max according to
    # the length of your cmdlist
    progressBar = QProgressBar()
    progressBar.setRange(0, len(cmdlist))
    
    # connect the worker's progress signal with the progressbar
    workerObject.madeProgress.connect(progressBar.setValue)
    
    # start the thread (starting your worker at the same time)
    workerThread.start()
    

    【讨论】:

    • 好的,塞巴斯蒂安...现在可以工作了...非常感谢您的帮助。需要添加 start() 方法将其与 python 线程相结合...
    猜你喜欢
    • 1970-01-01
    • 2018-10-10
    • 2011-12-13
    • 1970-01-01
    • 2022-10-15
    • 1970-01-01
    • 2015-09-02
    • 2018-08-31
    • 1970-01-01
    相关资源
    最近更新 更多