Python tkinter GUI冻结/崩溃


from Tkinter import *
import tkFileDialog
import tkMessageBox
import os
import ttk
import serial
import timeit
import time
######################################################################################
class MyApp:
    def __init__(self, parent):
########################################################
#Setup Frames
        self.MiddleFrame = Frame(parent) #Middle Frame
        self.MiddleFrame.pack()
        #GLOBAL VARIABLES
        self.chip_number = 0 #number of chip testing
###########################################
        #Middle Frame setup  
        Label(self.MiddleFrame, text='Done').grid(row=8, column=1, sticky = E)
        self.Done = Canvas(self.MiddleFrame, bg="yellow", width=10, height=10)
        self.Done.grid(row=8, column=2)         
        Label(self.MiddleFrame, text='Chip Number:').grid(row=9, column=1, sticky = E)
        #start button
        self.button1 = Button(self.MiddleFrame,state=NORMAL, command= self.start_pre)
        self.button1["text"]= "START"
        self.button1.grid(row=1, column=2, sticky = E)
########################################### 
#Action of Start Button
    def start_pre(self):
        x = 0
        while x<10000:         
            self.start_button()
            x=x+1
#Talking to Board
    def start_button(self):
        #increase chip count number and update
        self.chip_number += 1
        Label(self.MiddleFrame, text=str(self.chip_number)).grid(row=9, column=2, sticky = E)
        #reset-yellow
        self.reset_color()          
        print "Still Working", self.chip_number
        self.Done.configure(background="green")
        self.Done.update_idletasks()                 
###############################################################
#Color Boxes
#Reset
    def reset_color(self):
        self.Done.configure(background="yellow")
        self.Done.update_idletasks() 
###############################################################################################################
#Start Programs
root = Tk() #makes window
root.title("Interface")
myapp = MyApp(root) #this really runs program
root.mainloop() #keep window open                                                                           
在我的程序中,我首先按开始键。我将打印"仍在工作",GUi将更新芯片编号并一遍又一遍地闪烁完成灯。开始按钮转到将执行10000次的函数。然而在3000次迭代后,gui冻结,但程序仍然打印"仍在工作"。如何防止gui崩溃?

你的代码有很多问题。首先,这从根本上是有缺陷的:

while self.stop == True:         
    self.start_button()
    time.sleep(0.5)

你根本不能指望GUI用这样的代码正常运行。一般来说,你不应该让GUI的主线程调用sleep。导致sleep会阻止事件循环处理任何事件,包括低级事件,如刷新屏幕的请求。

sleep的使用已经在stackoverflow上被询问和回答了很多次。你可能会发现其中一些问题很有用。例如

  • windows认为tkinter没有响应
  • Python Tkinter坐标函数在循环内不移动画布对象
  • 如何在Tkinter中更新部件?
  • 多操作
  • Python Tkinter秒表错误

您有另一个属于内存泄漏类别的问题。从那个while循环中,无限地调用self.start_button()。这大约每秒发生一次,因为在循环中调用睡眠半秒,在start_button中调用另半秒。

每次调用start_button时,您创建另一个标签小部件,将其堆叠在第9行第2列中所有先前小部件的顶部。最终这将导致您的程序崩溃。我很惊讶它会使你的程序这么快就失败,但这不是重点。

我的建议是从一个简单的例子开始,除了每秒更新一个标签之外什么都不做。让它工作,这样你就能理解基本的机制。然后,一旦它开始工作,您就可以添加从串行端口读取的代码。

我可以建议您重新编写以下代码吗?如果需要,您可以将其移植回Python 2,但您的程序已被重写为使用Python 3,并且已被设计为使用tkinter使用after方法调度未来事件的能力。希望您会发现代码更容易理解。

import collections
import timeit
import tkinter
def main():
    root = Application()
    root.setup()
    root.mainloop()
class Application(tkinter.Tk):
    def setup(self):
        mf = self.__middle_frame = tkinter.Frame(self)
        self.__middle_frame.grid()
        bf = self.__bot_frame = tkinter.Frame(self)
        self.__bot_frame.grid()
        self.__port_set = False
        self.__chip_number = 0
        self.__chip_pass_num = 0
        self.__chip_fail_num = 0
        self.__chip_yield_num = 0
        self.__stop = True
        self.__widgets = collections.OrderedDict((
            ('COT', 'Continuity Test'), ('CHE', 'Chip Erase'),
            ('ERT', 'Erase Test'), ('WRT', 'Write Test'),
            ('WIRT', 'Wire Reading Test'), ('WIT', 'Wire Reading Test'),
            ('WRAT', 'Write All Test'), ('DO', 'Done')))
        for row, (key, value) in enumerate(self.__widgets.items()):
            label = tkinter.Label(mf, text=value+':')
            label.grid(row=row, column=0, sticky=tkinter.E)
            canvas = tkinter.Canvas(mf, bg='yellow', width=10, height=10)
            canvas.grid(row=row, column=1)
            self.__widgets[key] = label, canvas
        self.__cn = tkinter.Label(mf, text='Chip Number:')
        self.__cn.grid(row=8, column=0, sticky=tkinter.E)
        self.__display = tkinter.Label(mf)
        self.__display.grid(row=8, column=1, sticky=tkinter.E)
        self.__button = tkinter.Button(bf, text='START',
                                       command=self.__start_pre)
        self.__button.grid(sticky=tkinter.E)
    def __start_pre(self):
        self.__button['state'] = tkinter.DISABLED
        self.__start_button(0)
    def __start_button(self, count):
        if count < 100:
            self.__chip_number += 1
            self.__display['text'] = str(self.__chip_number)
            self.__widgets['DO'][1]['bg'] = 'yellow'
            start_time = timeit.default_timer()
            print('Still Working:', self.__chip_number)
            self.after(500, self.__end_button, count)
        else:
            self.__button['state'] = tkinter.NORMAL
    def __end_button(self, count):
        self.__widgets['DO'][1]['bg'] = 'green'
        self.after(500, self.__start_button, count + 1)
if __name__ == '__main__':
    main()

最新更新