在窗口中保留小部件的问题

时间:2014-04-07 16:39:33

标签: python tkinter

我使用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()

这就像我可以获得代码那样简单,而不会失去我希望它拥有的主要功能。最终版本有很多其他的东西,但看起来这个代码给了我这些问题。

1 个答案:

答案 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)是首选的解决方案,因为我没有看到你需要销毁它们然后重新创建它们的任何理由。