从pickle文件加载并修改tkinter GUI

2 投票
1 回答
1650 浏览
提问于 2025-04-17 07:19

我在从一个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秒左右更新一次并重新绘制界面)。

我尝试过updateupdate_idletasks,但似乎都无法重新加载pickle并根据新信息重新绘制。

1 个回答

3

主循环是你的根部件用来监听和响应输入及其他事件的地方,比如鼠标点击、键盘按键和操作系统发来的信号。通过使用 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)

撰写回答