这是我关于SO的第一个问题。我正在尝试解决UI问题,并且(我认为)有一些具体的问题。为了简化事情并澄清我的推理,让我描述一个例子,同时省略应用程序的不相关部分,我想解决这个问题:
假设我们有一个非常小的Python应用程序,它使用tkinter作为GUI。它所做的就是,如果用户点击“创建文件”按钮并且文件不存在,它会询问用户是否应该使用messagebox.askyesno()创建文件。文件处理由一个单独的FileHandler()类完成,该类没有任何UI的概念,并使用Python队列进行异步通信。这是为了使UI易于互换,我希望保持这一点。
我们的tk主根查询输出队列并将消息框的结果放入输入队列。但这不能使用线程,因为影响GUI的方法只能从主循环中调用。
所以我最后使用Widget.after()轮询输出队列,并在单独的线程中执行文件handlig,以避免死锁。这有效,但这被认为是一个很好的解决方案吗?我怀疑是因为
基本上我想异步创建消息框而不需要轮询的开销。是不是有更好的解决方案可以避免它?
这是我的示例代码(使用Python 3.4.2测试):
main.py
from tkinter import *
from tkinter import messagebox
from filehandler import FileHandler
class MyGUI():
poll_id = None
fh = None
def poll(self):
self.poll_cancel()
try:
notification = self.fh.outqueue.get_nowait()
except:
self.poll_id = self.root.after(50, self.poll)
return
if notification == 1:
yesno = messagebox.askyesno("Question",
"Do you want to create the file?")
self.fh.inqueue.put(yesno)
self.fh.outqueue.task_done()
self.poll_id = self.root.after(50, self.poll)
def poll_cancel(self):
if self.poll_id is not None:
self.root.after_cancel(self.poll_id)
self.poll_id = None
def create_file(self):
self.fh.create_file()
def __init__(self, fh):
self.fh = fh
self.root = Tk()
self.root.btn = Button(self.root, text="Open file",
command=self.create_file)
self.root.btn.pack()
self.poll()
self.root.mainloop()
if __name__ == "__main__":
MyGUI(FileHandler())
filehandler.py
import os
import queue
import threading
class FileHandler():
inqueue = None
outqueue = None
def __init__(self):
self.inqueue = queue.Queue()
self.outqueue = queue.Queue()
def create_file(self):
threading.Thread(target=self.create_file_thread).start()
def create_file_thread(self):
if not os.path.exists("file"):
self.outqueue.put(1)
yesno = self.inqueue.get()
if yesno == 1:
try:
with open("file", 'a'):
os.utime("file")
except Exception as e:
print(e)
self.inqueue.task_done()