Python tkinter GUI冻结/崩溃

时间:2015-07-23 15:01:21

标签: python tkinter

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崩溃?

2 个答案:

答案 0 :(得分:2)

您的代码存在许多问题。首先,这从根本上是有缺陷的:

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

您根本不能指望GUI能够像这样的代码正常运行。作为一般经验法则,您永远不应该拥有GUI调用的主线程sleep。导致sleep阻止事件循环处理任何事件,包括低级事件,例如刷新屏幕的请求。

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

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

每次调用start_button时,都会创建另一个标签小部件,并将其堆叠在第9行第2列中的所有先前小部件之上。最终,这会导致程序崩溃。我很惊讶它导致你的程序如此迅速地失败,但那就是重点。

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

答案 1 :(得分:0)

我建议您重新开始使用以下代码吗?如果需要,您可以回到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()