我使用tkinter创建了一个gui,它每隔一分钟刷新一次(在这个例子中,我更快地刷新它,以便我可以更快地看到问题)。然而,当它进行大约300次或更多次重绘时,所有内容都从画布上移开并移到屏幕的左上角并保持在那里(为了达到300次刷新,我通过调整窗口来帮助它,它也会发生当它只是坐在那里)。为什么会这样做呢?
有关如何解决此问题的任何想法?
该程序应该能够保持开放至少一周,可能更长,每分钟都在刷新。
from Tkinter import *
import tkFont
import ttk
import math
import time
import os
numT = 15
cellWidth = 325
from win32api import GetSystemMetrics
wWidth = GetSystemMetrics (0)
wHeight = GetSystemMetrics (1)
class GUI(Frame):
def __init__(self, root):
Frame.__init__(self, root)
self.parent = root
self.canvas = Canvas(self.parent, relief=SUNKEN, background="red")
self.entry = Frame(self.canvas, background="black", bd=1)
self.canvas.pack(fill=BOTH, expand=1)
self.entry.pack(fill=BOTH, expand=1, anchor="nw")
def createMatrix(self, rows, columns):
tContainers = 0
for i in range(rows):
for j in range(columns):
container = Frame(self.entry, background="yellow")
entry = ttk.Label(container, text="%d, %d"%(i,j))
container.grid_propagate(False)
container.config(width=325, height=185)
container.grid(column=j, row=i, padx=1, pady=1)
entry.grid(column=j, row=i)
tContainers = tContainers + 1
if tContainers > numT:
tContainers = tContainers - 1
container.grid_forget()
slaves = self.entry.grid_slaves()
return slaves
def resize(self, event):
global wWidth
global wHeight
wWidth = event.width
wHeight = event.height
self.refreshWindow()
def initWindow(self):
self.cells = numT*cellWidth
initWidth = self.canvas.winfo_screenwidth()
if self.cells > initWidth:
self.columns = (initWidth/cellWidth)
else:
self.columns = numT
self.rows = float(numT)/self.columns
self.rows = int(math.ceil(self.rows))
self.slaves = self.createMatrix(self.rows, self.columns)
def resizeWindow(self):
width = wWidth
height = wHeight
if self.cells > width or self.cells <= width:
for wgt in self.slaves:
wgt.grid_forget()
if self.cells > width:
self.columns = (width/cellWidth)
else:
self.columns = numT
if width < cellWidth:
self.columns = 1
self.rows = float(numT)/self.columns
self.rows = int(math.ceil(self.rows))
self.slaves = self.createMatrix(self.rows, self.columns)
else:
self.slaves = self.createMatrix(self.rows, self.columns)
def refreshWindow(self):
self.resizeWindow()
self.after (500, self.refreshWindow)
def Run(self):
self.initWindow()
self.canvas.bind("<Configure>", self.resize)
if __name__ == "__main__":
root = Tk()
root.configure(background="black")
root.wm_minsize(750, 500)
test = GUI(root)
test.Run()
root.mainloop()
这就像我可以获得代码那样简单,而不会失去我希望它拥有的主要功能。最终版本有很多其他的东西,但看起来这个代码给了我这些问题。
答案 0 :(得分:1)
让我们做一点数学。
我们假设您正在创建一个4x4矩阵。这是16个领域。在每个区域中,您将创建一个Frame和一个Label,总共32个小部件。你这样做两次,你永远不会破坏这些小部件。这意味着您每秒创建64个小部件。仅仅一分钟后,您最终获得了3,840个小部件。 10分钟后,你有38,400个小部件。
你说你想要这个熬夜一个星期。这一天是7天* 24小时*一小时60分钟*一分钟60秒*每秒64小时。一周后,您将创建38,707,200个小部件。您还遇到第二个问题,即您从refreshWindow
事件和窗口调整大小时调用after
。因此,每次窗口调整大小时,它都会启动另一个小部件创建循环,这会添加一个全新的小部件创建循环。因此,如果您的窗口在本周开始时只调整一次,那么您最终将创建7600万个小部件。双倍,三倍,四倍,如果窗口调整大小不止一次。
问题在于你不断创建小部件,但是你永远不会销毁它们,所以最终你会耗尽系统资源并导致Tkinter以可能的意外方式失败。当您致电grid_forget
时,您无法销毁小部件,只需将其从视图中移除即可。他们仍然存在,他们仍然记忆犹新。如果您打算再也不使用小部件,则应调用他们的destroy
方法。 Tkinter很好地扩展,但是当您创建数百万个小部件时,期望它失败是合理的。
解决方案要么是a)在创建更多内容之前销毁小部件,要么b)学习如何重用现有小部件。 (b)是首选的解决方案,因为我没有看到你需要销毁它们然后重新创建它们的任何理由。