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

5
我有一个pyqt的GUI,并调用了一个长时间运行的进程(ffmpeg),我将其放在一个单独的线程中以避免阻塞GUI。然后,当较长命令列表中的一个命令完成时,我想更新进度条。问题是,我无法在工作线程之外调用GUI线程中的函数。所以我让工作线程运行一个计时器,但当我使用while循环并读取计时器值更新进度条时,GUI再次被阻塞。我该如何解决这个问题?目前我正在使用Python threading而不是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)
1个回答

7
简言之:使用 QThread 并运用 Qt 的信号与槽连接,在线程间通信时它们是首选。
以下提供的答案为例: https://dev59.com/yGw15IYBdhLWcg3wLIo2#6789205 在您的情况下,采用上述示例中的 "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()

然后将这个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()

好的Sebastian...现在它可以工作了...非常感谢你的帮助。需要添加start()方法并将其与Python线程结合使用... - rainer

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接