-1
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                                                                           

With my program, i first push the start button. I will print "still working" and the GUi will update chip number and blink done light over and over. The start button go to function that will execute 10000 times. However after 3000 iterations, the gui freeze, but the program is still print "still working". How do I keep the gui from crashing?

Vema Reddy
  • 45
  • 2
  • 2
  • 7
  • Probably you should put the method in a separate thread. See here http://stackoverflow.com/questions/16745507/tkinter-how-to-use-threads-to-preventing-main-event-loop-from-freezing – a_guest Jul 23 '15 at 15:15
  • 1
    Try using Tkinter's `after` instead of `sleep` – tobias_k Jul 23 '15 at 15:22
  • FWIW, you should use `time.time()` instead of `timeit.default_timer()`. Both names refer to the same function, but `time.time()` will make more sense to people reading your code. – PM 2Ring Jul 23 '15 at 15:28
  • I not sure how I would use the after method – Vema Reddy Jul 23 '15 at 16:15
  • I updated my code and got rid of the sleep. Still trying to figure out solution – Vema Reddy Jul 23 '15 at 16:49

2 Answers2

5

There are many problems with your code. For one, this is fundamentally flawed:

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

You simply can't expect a GUI to behave properly with code like that. As a general rule of thumb you should never have the main thread of a GUI call sleep. Causing sleep prevents the event loop from processing any events, including low level events such as requests to refresh the screen.

The use of sleep has been asked and answered many times on stackoverflow. You might find some of those questions useful. For example,

You have another problem that falls into the category of a memory leak. From that while loop, you call self.start_button() indefinitely. This happens about once a second, due to sleep being called for half a second in the loop, and another half a second in start_button.

Each time you call start_button, you create another label widget that you stack on top of all previous widgets in row 9, column 2. Eventually this will cause your program to crash. I'm surprised that it causes your program to fail so quickly, but that's beside the point.

My recommendation is to start over with a simple example that does nothing but update a label every second. Get that working so that you understand the basic mechanism. Then, once it's working, you can add in your code that reads from the serial port.

Community
  • 1
  • 1
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
1

May I suggest that you start over with the following code? You can port in back to Python 2 if needed, but your program has been rewritten to use Python 3 and has been designed to use tkinter's ability to schedule future events with the after methods. Hopefully, you will find the code easier to follow.

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()
Noctis Skytower
  • 21,433
  • 16
  • 79
  • 117