<p>再次感谢你。join()肯定是问题的一部分。问题的另一部分是MIGUI类无法知道长时间运行的进程何时完成(可能是因为它已经运行了自己的进程,也可能是因为它被中止了)。在低级工作进程和UI层之间需要一个额外的消息传递层。我确实尝试过使用threading.Event,但没有成功,并且考虑过使用队列</p>
<p>我的解决方案是使用pubsub(<a href="https://github.com/schollii/pypubsub" rel="nofollow noreferrer">https://github.com/schollii/pypubsub</a>)工作层可以发送关于各种主题的消息,UI层和接口层可以设置侦听器来对接收到的数据执行操作</p>
<p>在我的例子中,Import.doImport方法在完成时发送一条状态消息。然后,MIGUI侦听器可以相应地触发Start/Abort按钮</p>
<p>为了确保pubsub的实现按计划进行,我还设置了一个tkinterprogressbar。doImport方法发送一个带有完成百分比的proges消息。这反映在屏幕上的Progressbar中</p>
<p>一个旁注-在我的原始版本中,我必须在按钮上使用.update(),才能让它们显示出来。既然我们不再封锁了,这就没必要了</p>
<p>在这里发布完整的工作解决方案,显示pubsub实现</p>
<pre><code>import tkinter as tk
from tkinter import ttk
import threading
import time
from pubsub import pub
class MIGUI():
def __init__(self, master):
self.master = master
self.mediaImporter = MediaImporter()
self.startButton = ttk.Button(self.master, text='Start', command=self.startCallback)
self.startButton.pack()
self.abortButton = ttk.Button(self.master, text='Abort', command=self.abortCallback)
self.abortButton.state(['disabled'])
self.abortButton.pack()
self.progress = ttk.Progressbar(self.master, length=300)
self.progress.pack()
pub.subscribe(self.statusListener, 'STATUS')
pub.subscribe(self.progressListener, 'PROGRESS')
def statusListener(self, status, value):
print('MIGUI', status, value)
if status == 'copying' and (value == 'finished' or value == 'aborted'):
self.startButton.state(['!disabled'])
self.abortButton.state(['disabled'])
def progressListener(self, value):
print('Progress %d' % value)
self.progress['maximum'] = 100
self.progress['value'] = value
def startCallback(self):
print('startCallback')
self.abortButton.state(['!disabled'])
self.startButton.state(['disabled'])
self.x = threading.Thread(target=self.mediaImporter.startImport)
self.x.start()
# original issue had join() here, which was blocking.
def abortCallback(self):
print('abortCallback')
self.mediaImporter.abortImport()
class MediaImporter():
""" Interface between user (GUI / console) and worker classes """
def __init__(self):
self.Import = Import()
#other worker classes exist too
pub.subscribe(self.statusListener, 'STATUS')
def statusListener(self, status, value):
#perhaps do something
pass
def startImport(self):
self.Import.start()
def abortImport(self):
self.Import.abort()
class Import():
""" Worker
Does not know anything about other non-worker classes or UI.
It does use pubsub to publish messages - such as the status and progress.
The UI and interface classes can subsribe to these messages and perform actions. (see listener methods)
"""
def __init__(self):
self._wantAbort = False
def start(self):
self._wantAbort = False
self.doImport()
def abort(self):
pub.sendMessage('STATUS', status='abort', value='requested')
self._wantAbort = True
def doImport(self):
self.max = 13
pub.sendMessage('STATUS', status='copying', value='started')
for i in range(1,self.max):
#actual code has nested for..loops
progress = ((i+1) / self.max * 100.0)
pub.sendMessage('PROGRESS', value=progress)
time.sleep(.1)
if self._wantAbort:
pub.sendMessage('STATUS', status='copying', value='aborted')
return
pub.sendMessage('STATUS', status='copying', value='finished')
def main():
gui = True
console = False
if gui:
root = tk.Tk()
app = MIGUI(root)
root.mainloop()
if console:
#do simple console output without tkinter - threads not necessary
pass
if __name__ == '__main__':
main()
</code></pre>