gpt4 book ai didi

python - 从 Tkinter 运行线程并等待它完成

转载 作者:行者123 更新时间:2023-11-28 16:40:15 26 4
gpt4 key购买 nike

我有一个 tkinter 应用程序(作为主线程运行),在其中我打开了新的顶级窗口 - 它是一个日志窗口打印测试结果(测试是使用 selenium webdriver 执行的)。该对话框也是所有测试的调用者。

所以我想显示对话框(作为顶层,整个应用程序还有一个窗口),运行测试,等到测试完成并打印结果,然后对另一个测试单元执行相同的操作。但我不想在测试期间让窗口卡住。

我试过使用线程,但显然它可以像那样工作。在这种情况下,对话甚至在测试完成后才开始。

这是对话窗口的代码。

class TestDialog(tkinter.Toplevel):

def __init__(self, parent, tester, url):
super().__init__(parent)
self.parent = parent
self.webtester = tester;

self.__initComponents()

self.run(url)

self.wait_window(self)

def __initComponents(self):
self.transient(self.parent)

frame = tkinter.Frame(self)

self._tarea = tkinter.Text(frame, state='disabled',wrap='none', width=55, height=25)

vsb = tkinter.Scrollbar(frame, orient=tkinter.VERTICAL, command=self._tarea.yview)
self._tarea.configure(yscrollcommand=vsb.set)


self._tarea.grid(row=1, column=0, columnspan=4, sticky="NSEW", padx=3, pady=3)
vsb.grid(row=1, column=4, sticky='NS',pady=3)
frame.grid(row=0, column=0, sticky=tkinter.NSEW)

frame.columnconfigure(0, weight=2)
frame.rowconfigure(1, weight=1)

window = self.winfo_toplevel()
window.columnconfigure(0, weight=1)
window.rowconfigure(0, weight=1)

self.bind("<Escape>", self.close)

self.protocol("WM_DELETE_WINDOW", self.close)
self.grab_set()

def appendLine(self, msg):
self._tarea['state'] = 'normal'
self._tarea.insert("end", msg+'\n')
self._tarea['state'] = 'disabled'

def run(self, url):

self.appendLine("Runneing test #1...")

try:
thr = threading.Thread(target=self.webtester.urlopen, args=(url,))
thr.start()
except:
pass

thr.join()

self.webtester.urlopen(url)

self.appendLine("Running test #2")
try:
thr = threading.Thread(target=self.webtester.test2)
thr.start()
except:
pass

def close(self, event=None):
self.parent.setBackgroundScheme(DataTreeView.S_DEFAULT)
self.parent.focus_set()
self.destroy()

这个对话框可以通过以下方式从父窗口打开:

testDialog = TestDialog(self.parent, self._webtester, url)

感谢您的任何建议。

最佳答案

要防止 GUI 卡住,您需要 self.run() 快速结束。它需要产生一个线程,启动线程,然后结束:

import Queue
sentinel = object()
root = tkinter.Tk()

...
def run(self, url):
outqueue = Queue.Queue()
thr = threading.Thread(target=self.run_tests, args=(url, outqueue))
thr.start()
root.after(250, self.update, outqueue)

现在这个线程运行的函数可以运行很长时间了:

def run_tests(self, url, outqueue):
outqueue.put("Running test #1...")
self.webtester.urlopen(url)
outqueue.put("Running test #2")
self.webtester.test2()
outqueue.put(sentinel)

但是因为 Tkinter 期望所有 GUI 调用都源自单个线程,所以这个生成的线程不能进行任何 GUI 调用。为了让它与 GUI 交互,您可以通过 Queue.Queue 发送输出(例如状态更新消息)并同时让主 Tkinter 线程监控此 Queue.Queue 定期(通过调用 root.after):

def update(self, outqueue):
try:
msg = outqueue.get_nowait()
if msg is not sentinel:
self.appendLine(msg)
root.after(250, self.update, outqueue)
else:
# By not calling root.after here, we allow update to
# truly end
pass
except Queue.Empty:
root.after(250, self.update, outqueue)

关于python - 从 Tkinter 运行线程并等待它完成,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20161111/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com