<p>@Victor Domingos的提到对您的情况非常有用,但是您真正的问题是您自己的代码!首先,看看你的应用程序的结构,明白它很弱,没有冒犯性(你甚至把一个<code>master</code>传递给一个函数来<code>destroy</code>它)。所以我建议您阅读Python中的类和继承(如果您还没有),然后看看<a href="https://stackoverflow.com/questions/17466561/best-way-to-structure-a-tkinter-application">here</a>。在</p>
<p>下一站-你的重定向器。您重新分配了<code>sys.stdout.write</code>,但从未保留它-因此它是另一个弱点。好吧,假设现在您保留了它,但是如果我们保持面向对象的方法-我更喜欢<a href="https://stackoverflow.com/questions/3333334/stdout-to-tkinter-gui">this</a>选项。在</p>
<p>另外,真的有必要<code>destroy</code>这个<code>master</code>?对于输出,您可以使用一个<code>Toplevel</code>小部件,如果您删除<code>master</code>只是为了避免两个<code>mainloop</code>。<a href="https://stackoverflow.com/questions/24866221/hide-the-root-window-when-a-toplevel-window-is-opened-and-make-it-reappear-when">You can even hide ^{<cd9>} while ^{<cd6>} is active</a>。太棒了,不是吗?在</p>
<p>最后,回答你关于解决方案的问题。没有直接的解决办法,只有一个:阅读并尝试。你已经回答了为什么<em>为什么</em><code>mainloop</code>停止一切,但是你的问题非常广泛。在</p>
<p>我试着复制你的完整程序(2窗口应用程序,第一个用户输入,第二个类似控制台和线程的打印任务示例),下面是一个代码:</p>
<pre><code># imports:
try:
import tkinter as tk
except ImportError:
import Tkinter as tk
import sys
import string
import random
import threading
# classes:
class ReStdout:
# common stdout-redirector
def __init__(self, target_widget, start_redirection=True):
self.text_console = target_widget
if start_redirection:
self.start_redirection()
def __del__(self):
self.stop_redirection()
def __exit__(self, exc_type, exc_val, exc_tb):
self.stop_redirection()
def __enter__(self):
pass
def flush(self):
pass
def write(self, stdout_line):
self.text_console.insert('1.0', stdout_line)
def start_redirection(self):
sys.stdout = self
@staticmethod
def stop_redirection():
sys.stdout = sys.__stdout__
class App(tk.Tk):
# common tk app
def __init__(self):
tk.Tk.__init__(self)
self.resizable(width=True, height=False)
self.minsize(width=250, height=25)
self.some_entry = tk.Entry(self)
self.some_entry.insert(0, 'You can pass something to Spawner!')
self.some_entry.pack(expand=True, fill='x')
self.start_spawner_button = tk.Button(self, text='Start Spawner', command=self.spawn_spawner)
self.start_spawner_button.pack(expand=True, fill='x')
def spawn_spawner(self):
Spawner(self, self.some_entry.get())
def close_app(self):
self.destroy()
class Spawner(tk.Toplevel):
# common tk app - task spawner
def __init__(self, master, entry_string):
tk.Toplevel.__init__(self, master)
self.resizable(width=False, height=False)
self.preserved_count = threading.active_count()
self.master = master
self.master.withdraw()
self.spawn_task_button = tk.Button(self, text='Spawn Task', command=spawn_task)
self.spawn_task_button.pack(expand=True, fill='x')
self.quit_button = tk.Button(self, text='Quit', command=self.close_app)
self.quit_button.pack(expand=True, fill='x')
self.text = tk.Text(self, bg='black', fg='white')
self.text.pack(expand=True, fill='both')
self.stdout = ReStdout(self.text)
self.protocol('WM_DELETE_WINDOW', self.close_app)
# print what have been passed
print('Users Input: %s' % entry_string)
# let's spawn something right now
# after here just for example
# try to use it w/o after
self.after(500, multi_spawn)
def close_app(self):
if threading.active_count() == self.preserved_count:
self.stdout.stop_redirection()
self.master.deiconify()
self.destroy()
else:
# code to handle threads
print('\n**** Cant quit right now! ****\n')
# non - class functions:
def multi_spawn(count=1):
for _ in range(count):
spawn_task()
def spawn_task():
task_count = threading.active_count()
task = threading.Thread(target=lambda: common_task(comment='%d printing task' % task_count,
iteration_count=random.randint(1, 10)))
task.start()
def common_task(comment, iteration_count=1):
# example task wait + print
task_numb = comment.split(None, 1)[0]
print('\nTask spawned:\n%s\nIteration count: %d\n' % (comment, iteration_count))
for _ in range(iteration_count):
threading.Event().wait(1)
print('Task: %s \t Iteration: %d \t Generated: %s' % (task_numb, _ + 1, generate_smth()))
print('\nTask %s completed!' % task_numb)
def generate_smth(size=6, chars=string.ascii_uppercase + string.digits):
# generate random
return ''.join(random.choice(chars) for _ in range(size))
# entry-point:
print('Just another example from SO')
app = App()
app.mainloop()
print('Beep')
</code></pre>
<p>如你所见-我从不在<code>mainloop</code>中被绊倒(当我不需要它的时候),因为我在事件上创建线程:Spawner的<code>__init__</code>(多亏了继承)和一个按钮点击事件。当然,这只是许多方法中的一种,但我希望现在你的问题对你更清楚些。在</p>