Python PyQT:如何从工作线程调用GUI函数?

rai*_*ner 4 python user-interface multithreading ffmpeg

我有一个pyqt gui并调用一个长进程(ffmpeg),我把它放在一个单独的线程上,以阻止gui.然后,我想在更长命令列表的一个命令完成时更新进度条.问题是,我无法在工作线程中调用gui线程中的函数.所以我在工作线程中运行一个自动收报机,但是当我用while循环更新进度条并读取自动收报机价值时,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)
Run Code Online (Sandbox Code Playgroud)

seb*_*ian 5

简而言之:移动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()
Run Code Online (Sandbox Code Playgroud)

然后将此worker移动到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()
Run Code Online (Sandbox Code Playgroud)