从pickle文件加载并修改tkinter GUI
我在从一个pickle文件加载图形用户界面(GUI)时遇到了一些麻烦。
我虽然能做到我想要的,但结果并不是完全如我所预期的,我也不确定这样做是否正确。
这是一个简化的基本GUI示例(你不需要深入理解这段代码,这不是主要问题):
tableRel = {}
master = Tk()
tableOrders = pickle.load(open(r"\\VIERNES7-3\Documentos c\sharedTableOrders.p","rb"))
count = 0
lOfKeys = tableOrders.keys()
numOfTables = len(lOfKeys)
for rowN in range((numOfTables /10)+1):
for colN in range(10):
if count == numOfTables:
break
tableN = (colN+1)+(10*(rowN))
f = Frame(master,height=600,width=200, bd=1, relief=SUNKEN)
f.grid(row=rowN, column=colN, pady=15, padx= 0)
Label(f, text="Mesa: " + str(lOfKeys[count])).pack(side = TOP)
scrollbar = Scrollbar(f, orient=VERTICAL)
listbox = Listbox(f, yscrollcommand=scrollbar.set, width=19)
tableRel[listbox] = lOfKeys[count]
scrollbar.config(command=listbox.yview)
scrollbar.pack(side=RIGHT, fill=Y)
listbox.pack(side=TOP)
listbox.bind("<Double-Button-1>", hideOrder)
listbox.bind("<Return>", hideOrder)
index = 0
listbox.delete(0, END)
for y in tableOrders[lOfKeys[count]]["orders"]:
#print tableOrders[x]
if (y["kitchen"] == "si" or y["category"] != "Bebidas") and y["ready"] == "no":
listbox.insert(END, y["name"])
#ordersByIndex[index] = y["name"]
if y["canceled"] == "si":
listbox.itemconfig(index, bg="red")
#tablesByIndex[index] = x
index += 1
count += 1
loadFile()
mainloop()
现在我有点困惑的地方是,我不太明白mainloop()
这个无限循环的概念。
它到底是重复做什么呢?
让我感到困扰的是,如果我在文件的任何地方放一个打印语句,它并不会一直重复打印,所以这段代码并没有被重新执行。
我基本上想要实现的是,在一段时间后,GUI能够重新加载,如果pickle文件有变化,GUI就能更新。
我通过把我的代码放在一个函数里(我们叫它updateGUI
),然后用master.after(5000, updateGUI)
来实现这个功能。
但这似乎不是最好的解决方案,因为所有的变化都是突然发生的(比如列表框中选择的选项和滚动条),我想这可以通过记住状态来解决。
不过我在想,是否有办法利用mainloop,让GUI在文件变化时“更新”(不需要去查找文件的变化,而是每10秒左右更新一次并重新绘制界面)。
我尝试过update
和update_idletasks
,但似乎都无法重新加载pickle并根据新信息重新绘制。
1 个回答
主循环是你的根部件用来监听和响应输入及其他事件的地方,比如鼠标点击、键盘按键和操作系统发来的信号。通过使用 after
,你可以利用主循环每隔 n 秒调用一次你的更新程序。
你还可以做的事情是记录界面闲置了多久(没有鼠标或键盘事件)。如果界面闲置了,并且有需要显示的变化,你可以立即更新它。如果界面没有闲置,就给用户一个提示,并提供一个手动触发更新的方式,直到界面再次闲置。这样,用户的工作就不会因为更新而被打断。
下面是一个简单的例子,展示了一个计时器,它会在鼠标移动或按键时重置。
import Tkinter as tk
class App():
def __init__(self, tick):
self.tick = tick
self.idle_time = 0
self.root = tk.Tk()
frame = tk.Frame(self.root, width=100, height=100)
frame.bind_all("<Motion>", self.reset_idle)
frame.bind_all("<Key>", self.reset_idle)
frame.pack()
self.root.after(self.tick, self.update_timer)
self.root.mainloop()
def update_timer(self):
print('Idle for %sms' % self.idle_time)
self.idle_time += self.tick
self.root.after(self.tick, self.update_timer)
def reset_idle(self, event):
self.idle_time = 0
app = App(1000)