1

My A-level project is an alarm system I have built using Tkinter that calculates the nearby traffic and changes your alarm time depending on how much the traffic will slow down or increase your journey.

I have calculated all the times I need, however, now I face the problem of having to constantly poll the current time to check it against my own, but this stops my tkinter functions from running. I am now fearing I should have used a different object orientated language.

How can I run these functions at the same time?

My code is below (I'm sure it is very inefficient).

def __init__(self, master = None):          #initialising the frame setup for windows

    Frame.__init__(self, master)
    self.master = master
    self.init_window()

def init_window(self):
    global lb,a,n
    self.master.title("Alarm")
    self.pack(fill=BOTH, expand =1)

    newButton = Button(self, text="New Alarm", command=self.new_window)     #create buttons and link to commands
    newButton.place(x=50, y=50)
    deleteButton = Button(self, text="Delete Alarm", command = self.alarmDelete)
    deleteButton.place(x=250, y=50)



    n=0                                         #loop through to find out how many rows are in the database
    for row in c.execute('SELECT Start Destination FROM stocks '):
        n = n + 1


    i=0
    remove=")"
    removed="("
    removing=","
    remover="'"
    a = [[0] * 14 for i in range(n)]             #load database into multidimensional array
    for row in c.execute('SELECT Start Destination FROM stocks '):
        a[i][0]= row
        temp=""
        for j in str(a[i][0]):              #remove unwanted characters from vars
            if j==remove or j == removed or j == removing :
                null=""
            else:
                temp=temp + str(j)
        a[i][0]=temp
        i = i + 1

    i=0
    for row in c.execute('SELECT End Destination FROM stocks '):
        a[i][1]= row
        temp=""
        for j in str(a[i][1]):
            if j==remove or j == removed or j == removing :
                null=""
            else:
                temp=temp + str(j)
        a[i][1]=temp
        i = i + 1

    i=0
    for row in c.execute('SELECT hArrival FROM stocks '):
        a[i][2]= row
        temp=""
        for j in str(a[i][2]):
            if j==remove or j == removed or j == removing or j==remover  :
                null=""
            else:
                temp=temp + str(j)
        a[i][2]=temp
        i = i + 1

    i=0
    for row in c.execute('SELECT mArrival FROM stocks '):
        a[i][3]= row
        temp=""
        for j in str(a[i][3]):
            if j==remove or j == removed or j == removing or j == remover:
                null=""
            else:
                temp=temp + str(j)
        a[i][3]=temp
        i = i + 1

    i=0
    for row in c.execute('SELECT Preperation Time FROM stocks '):
        a[i][4]= row
        temp=""
        for j in str(a[i][4]):
            if j==remove or j == removed or j == removing :
                null=""
            else:
                temp=temp + str(j)
        a[i][4]=temp
        i = i + 1

    i=0
    for row in c.execute('SELECT Day Date FROM stocks '):
        a[i][5]= row
        temp=""
        for j in str(a[i][5]):
            if j==remove or j == removed or j == removing :
                null=""
            else:
                temp=temp + str(j)
        a[i][5]=temp
        i = i + 1

    i=0
    for row in c.execute('SELECT Month Date FROM stocks '):
        a[i][6]= row
        temp=""
        for j in str(a[i][6]):
            if j==remove or j == removed or j == removing :
                null=""
            else:
                temp=temp + str(j)
        a[i][6]=temp
        i = i + 1

    i=0
    for row in c.execute('SELECT Year Date FROM stocks '):
        a[i][7]= row
        temp=""
        for j in str(a[i][7]):
            if j==remove or j == removed or j == removing :
                null=""
            else:
                temp=temp + str(j)
        a[i][7]=temp
        i = i + 1

    i=0
    for row in c.execute('SELECT AlarmName FROM stocks '):
        a[i][10]= row
        temp=""
        for j in str(a[i][10]):
            if j==remove or j == removed or j == removing or j ==remover :
                null=""
            else:
                temp=temp + str(j)
        a[i][10]=temp
        i = i + 1


    i=0
    for i in range(n):#convert times and dates to timestamp and datestamps
        a[i][8] = int(a[i][2])*3600 + int(a[i][3])*60
        a[i][9] = str(a[i][6]) + "/" + str(a[i][5]) + "/" + str(a[i][7])
        i=i+1

    i=0
    for i in range(n): #set all boolean value to true for later validation in calc
        a[i][12] = "00:00"
        a[i][12] = datetime.strptime(a[i][12], '%H:%M').time()
        i=i+1

    for i in range(n): #set all boolean value to true for later validation in calc
        a[i][13] = 0
        i=i+1

    i=0
    lb=Listbox(root)    #create listbox and insert values
    lb.pack()
    for i in range(n):
       for item in [str(a[i][10])]:
            lb.insert(END, item)
            i=i+1




    lb.bind('<Double-Button-1>', Window.alarmInfo) #if list item is double clicked call alarmInfo
    Window.alarmCalc(self) #call calculations


def alarmInfo(self):            #finds out which listbox item was selcted and prints info about it
    global lb,a,n
    listName = lb.get(ACTIVE)
    i=-1

    for i in range(n):
        if listName == a[i][10]:
            break
        else:
            i=i+1

    window = Toplevel(root)
    window.geometry("200x150")
    Label(window, text="Start Destination:").grid(row=0, sticky=W)
    Label(window, text=a[i][0]).grid(row=0,column=1, sticky=W)
    Label(window, text="End Destination:").grid(row=1, sticky=W)
    Label(window, text=a[i][1]).grid(row=1,column=1, sticky=W)
    Label(window, text="Arrival Time:").grid(row=2, sticky=W)
    Label(window, text=a[i][2] + ":" + a[i][3]).grid(row=2,column=1, sticky=W)
    Label(window, text="Preperation Time:").grid(row=3, sticky=W)
    Label(window, text=a[i][5]).grid(row=3,column=1, sticky=W)
    Label(window, text="Date").grid(row = 4,column=0, sticky=W)
    Label(window, text=a[i][9]).grid(row=4,column=1, sticky=W)
    Label(window, text="Alarm Name:").grid(row=5, sticky=W)#
    Label(window, text=a[i][10]).grid(row=5,column=1, sticky=W)

def alarmDelete(self):
    global a,n,lb
    listName = lb.get(ACTIVE)
    i=-1

    for i in range(n):
        if listName == a[i][10]:
            break
        else:
            i=i+1

    for row in c.execute('SELECT AlarmName FROM stocks '): #deletes selected item from database
        temp = row
        if listName in temp:
            c.execute('DELETE FROM stocks WHERE AlarmName=?', (listName,))
            conn.commit()
            break      


def new_window(self):           #create new window, and initialise layout
    global eSd,eEd,eAth,eAtm,ePt,eDd,eDm,eDy,eAn

    window = Toplevel(root)
    window.geometry("550x300")

    Label(window, text="Start Destination").grid(row=0, sticky=W)
    Label(window, text="End Destination").grid(row=1, sticky=W)
    Label(window, text="Arrival Time").grid(row=2, sticky=W)
    Label(window, text=":").grid(row=2, column=2, sticky=W)
    Label(window, text="Preperation Time").grid(row=3, sticky=W)
    Label(window, text="Alarm Name").grid(row=5, sticky=W)#

    eSd = Entry(window, width=5)
    eEd = Entry(window,width=5)
    eAth = Spinbox(window, from_=0, to=23)
    eAtm = Spinbox (window, from_=0, to=59)
    eDd = Spinbox (window, from_=1, to=31)
    eDm = Spinbox (window, from_=1, to=12)
    eDy = Spinbox (window, from_=2017, to=2019)
    ePt = Entry(window,width=5)
    eAn = Entry(window, width=20)

    eSd.grid(row=0, column=1, sticky=W)
    eEd.grid(row=1, column=1, sticky=W)
    eAth.grid(row=2, column=1, sticky=W)
    eAtm.grid(row=2,column=3, sticky=W)
    ePt.grid(row=3, column=1, sticky=W)
    eAn.grid(row=5, column=1, sticky=W)#

    Label(window, text="Date").grid(row = 4,column=0, sticky=W)
    eDd.grid(row = 4,column=3, sticky=W)
    Label(window, text="/").grid(row = 4,column=2, sticky=W)
    eDm.grid(row = 4,column=1, sticky=W)
    Label(window, text="/").grid(row = 4,column=4, sticky=W)
    eDy.grid(row = 4,column=5, sticky=W)#

    createButton = Button(window, text ="Create", command = self.create) #link to def create()
    createButton.place(x =50,y=150)


def create(self):
    global eSd,eEd,eAth,eAtm,ePt,eDd,eDm,eDy,eAn
    global sd,ed,ath,atm,pt,Dd,Dm,Dy,an
    val1 = False
    val2 = False
    val3 = True
    error=""

    sd = eSd.get()
    ed = eEd.get()
    ath = eAth.get()
    atm = eAtm.get()
    pt = ePt.get()
    Dd = eDd.get()
    Dm = eDm.get()
    Dy = eDy.get()
    an = eAn.get()#

    with open('zipcode.csv') as csvfile: #check through csv file to validate zipfiles
        reader = csv.reader(csvfile)
        for row in reader:
            for col in row:
                if col == sd:
                    val1= True
                if col ==ed:
                    val2 = True



    if len(pt) < 5:             #validate pt
        try:
            val3 = int(pt)
        except ValueError:
            val3 = False
    else:
        val3 = False


    if val1 == False and val2 == False and val3 == False:       #Compare boolean values to generate correct error message
        error = "Invalid Prep Time and Zipcodes"
    elif val1 == False and val3 == False :
        error = "Invalid Prep Time and Start Zipcode"
    elif val1 == False and val2 == False :
        error = "Invalid Zipcodes"
    elif val2==False and val3==False:
        error= "Invalid Prep Time and End Zipcode"
    elif val1 == False:
        error="Invalid Start Zipcode"
    elif val2==False:
        error="Invalid End Zipcode"
    elif val3==False:
        error = "Invalid Prep Time"


    if val1 == False or val2 == False or val3 == False:         #call different function depending on errors
        Window.valEr(self,error)
    else:
        Window.addList(self)



def valEr(self, error):             #displays error message
    window = Toplevel(root)
    window.geometry("100x100")
    Label(window, text=error).place(x=40, y=40)

def addList(self):
    global sd,ed,ath,atm,pt,Dd,Dm,Dy,an#
    if len(ath)< 2:                 #add preceeding 0's to single values to make calculations easier
        ath = "0" + ath
    if len(atm) < 2:
        atm = "0" + atm
    if len(Dm) < 2:
        Dm = "0" + Dm
    if len(Dd) <2:
        Dd = "0" + Dd
    pt = int(pt) * 60

    writeTo = (sd,ed,ath,atm,pt,Dd,Dm,Dy,an) #create tuple to make writing to database easier

    c.execute("INSERT INTO stocks VALUES(?,?,?,?,?,?,?,?,?)", writeTo) #insert data into database
    conn.commit()
                                          #################################################################################      

def alarmCalc(self):
    global a,n
    x=1000000000000000000000000
    i=0
    nowDate = date.today()
    temp =""
    temp2 = ""
    nowDate = str(nowDate.month) + "/" + str(nowDate.day) + "/" + str(nowDate.year) #get todays date
    for i in range(n):
        if nowDate == a[i][9]:
            Link= 'https://www.mapquestapi.com/directions/v2/route?key=YCGaovp1Y6fRO5f1RVWv2c1Qs9F4qF1N&from='+str(a[i][0])+'%2C+NY&to='+str(a[i][1])+'%2C+NY&outFormat=json&routeType=fastest&avoidTimedConditions=true&narrativeType=none'
            response = requests.get(Link)
            data = json.loads(response.text)
            rawtravelTime =int( data["route"]["time"])   #request and retrieve correct time
            #print(rawtravelTime)
            a[i][11]= int(a[i][8]) - int(a[i][4]) - rawtravelTime #calculate time in seconds
            #print(a[i][11])
            m, s = divmod(a[i][11], 60) # convert seconds to time using quotients
            h, m = divmod(m, 60)
            a[i][11]= str("%d:%02d:%02d" % (h, m, s))
            a[i][11] = a[i][11][:-3] #validation of time string
            if len(a[i][11]) < 5:
                a[i][11] = "0" + a[i][11]
            a[i][11] = datetime.strptime(a[i][11], '%H:%M').time() #turn into datetime object
            #print(a[i][11])
            nowTime = datetime.now().strftime('%H:%M') #get current time
            nowTime = datetime.strptime(nowTime, '%H:%M').time()
            #print(nowTime)
            if a[i][11] < nowTime or a[i][11] == nowTime or x < (10*3600) : #if alarm time = or exceeds current time call alarmTrig
                Window.alarmTrig(self)
            else:
                #print("NO")
                a[i][12] = datetime.combine(date.min, a[i][11]) - datetime.combine(date.min, nowTime)
                temp = str(a[i][12])
                print(temp)
                if len(temp) > 7: # gets time left in seconds
                    temp2 = temp[4:6]
                    temp = temp[:2]
                    a[i][13] = (int(temp) *3600) + (int(temp2) *60)
                    print(a[i][13])

                else:
                    temp2 = temp[2:4]
                    temp = temp[:1]
                    a[i][13] = (int(temp) *3600) + (int(temp2) *60)
                    print(a[i][13])
           # i=i+1
        else:
           # i=i+1
            print("not date")

    for i in range(n):   #finds smallest time
        if int(a[i][13]) < int(x):
            x=int(a[i][13])
            print(x)


    time.sleep(x/2) #make it wait half the time before recalc
    Window.alarmCalc



def alarmTrig(self):
    print("TRIG")
    winsound.PlaySound("*", winsound.SND_ALIAS)
    #Delete alarm
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
Becsaful
  • 11
  • 1
  • 1
    use threading for it – Gahan Dec 26 '17 at 12:40
  • Refer this thread : https://stackoverflow.com/questions/5568904/saving-the-state-of-a-program-to-allow-it-to-be-resumed – eiram_mahera Dec 26 '17 at 13:27
  • 1
    You've posted way too much code to be easily understood. How long does a single call to the polling function take? If it takes just a couple hundred ms or less, you can do that in tkinter without using threads or multiprocessing or asyncio, or anything fancy. If it takes longer than that, you'll probably need one of those. – Bryan Oakley Dec 27 '17 at 04:20
  • it takes a second or so... – Becsaful Jan 01 '18 at 18:52

0 Answers0