I created a tkinter alarm clock which is not responding after setting the alarm. The alarm sound is playing but after that I have to exit the application and re-run the code to set alarm once again .I have shared the code and screenshot of the app.
from tkinter import
import datetime
import time
from playsound import playsound
def Alarm(set_alarm_timer):
while True:
time.sleep(1)
actual_time = datetime.datetime.now()
cur_time = actual_time.strftime("%H:%M:%S")
cur_date = actual_time.strftime("%d/%m/%Y")
msg="Current Time: "+str(cur_time)
print(msg)
if cur_time == set_alarm_timer:
playsound("Audio.mp3")
break
def get_alarm_time():
alarm_set_time = f"{hour.get()}:{min.get()}:{sec.get()}"
Alarm(alarm_set_time)
window = Tk()
window.title("Alarm Clock")
window.geometry("400x160")
window.config(bg="#922B21")
window.resizable(width=False,height=False)
time_format=Label(window, text= "Remember to set time in 24 hour format!", fg="white",bg="#922B21",font=("Arial",15)).place(x=20,y=120)
addTime = Label(window,text = "Hour Min Sec",font=60,fg="white",bg="black").place(x = 210)
setYourAlarm = Label(window,text = "Set Time for Alarm: ",fg="white",bg="#922B21",relief = "solid",font=("Helevetica",15,"bold")).place(x=10, y=40)
hour = StringVar()
min = StringVar()
sec = StringVar()
hourTime= Entry(window,textvariable = hour,bg = "#48C9B0",width = 4,font=(20)).place(x=210,y=40)
minTime= Entry(window,textvariable = min,bg = "#48C9B0",width = 4,font=(20)).place(x=270,y=40)
secTime = Entry(window,textvariable = sec,bg = "#48C9B0",width = 4,font=(20)).place(x=330,y=40)
submit = Button(window,text = "Set Your Alarm",fg="Black",bg="#D4AC0D",width = 15,command = get_alarm_time,font=(20)).place(x =100,y=80)
window.mainloop()
.mainloop is some sort of while loop. So time.sleep() and while ... will mess with it. Use .after().
Edit: .place(),.pack() and .grid() geometry managers return None. And in python, the value of the last function is assigned.
here, it would be None, and might raise errors in future
def Alarm(set_alarm_timer):
actual_time = datetime.datetime.now()
cur_time = actual_time.strftime("%H:%M:%S")
if cur_time != set_alarm_timer:
msg="Current Time: "+str(cur_time)
print(msg)
window.after(1000,Alarm, set_alarm_timer)
else:
playsound("Audio.mp3")
...
submit = Button(window,text = "Set Your Alarm",fg="Black",bg="#D4AC0D",width = 15,command = lambda: Alarm(f"{hour.get()}:{min.get()}:{sec.get()}"),font=(20))
submit.place(x =100,y=80)
Related
import time
import tkinter as tk
from tkinter import messagebox
from tkinter import ttk
studyTime = True
root = tk.Tk()
while studyTime:
#Hour variable
hour = time.strftime("%H")
#Study Time1
studyTime_start1 = "18:00"
studyTime_end1 = "19:00"
#Study Time2
studyTime_start2 = "18:00"
studyTime_end2 = "20:00"
if hour < studyTime_end1 and hour > studyTime_start1:
Msg = tk.messagebox.showinfo(title = "Study Time", message = "Study Time")
HW_checkBtn = ttk.Button(root, text = "Study Time Started Click Here to Start")
HW_checkBtn.pack()
studyTime = False
if hour < studyTime_end2 and hour > studyTime_start2:
Msg1 = tk.messagebox.showinfo(title = "Study Time1", message = "Study Time1")
HW_checkBtn1 = ttk.Button(root, text = "Study Time Started Click Here to Start")
HW_checkBtn1.pack()
studyTime = False
root.mainloop()
I am trying to make a simple gui where you can press a button to start a a timer, and see it count down, similar to https://web.5217.app/, But I cannot get the timer to display in the gui, any help would be appreciated.
Also this is my first question so I may have done something wrong.
from tkinter import Tk, Button, DISABLED, Label, ACTIVE
import time
#main window configuration
root = Tk()
root.title ("PyDoro")
root.geometry ("400x400")
root.configure(bg = "#383838")
#colours for the text
Colour1 = "#c4c4c4"
Colour2 = "#292828"
def Date(): #Defines the date for displaying under the clock
day = time.strftime("%d")
month = time.strftime("%b") # %B can be used for full month
year = time.strftime("%Y")
Calendar.config (text= day + " " + month + " " + year)
def clock(): # for creating the clock
tizo = time.strftime("%X") #Find the time for your locale
Time.config (text = tizo)
Time.after (1000, clock)
Date() #calling the Date because it makes sense to do it here
def Stop():
print ("nothing")
def Start():
time_left = (50)
Stop.config (state = ACTIVE)
timer = Label (root, text = time_left)
timer.pack()
for i in range (50):
timer.config (text = time_left)
Start.after (1000) # this waits for 1 minute (60000 miliseconds)
#print (i) # This is just for debugging
time_left = time_left - 1
print (time_left)
Start = Button (root, text = "Start!", fg = Colour1, bg = Colour2, padx = 40, command = Start)
Stop = Button (root, text = "stop", fg = Colour1, bg = Colour2, state = DISABLED)
Time = Label (root, text="", font = ("Helvetica", 50), fg = Colour1, bg = "#383838")
Time.pack (pady = 5)
Calendar = Label (root, font = ("Helvetica", 12), fg = Colour1, bg = "#383838")
Calendar.pack (pady = 5)
Start.pack (pady = 10)
Stop.pack (pady = 10)
clock()
root.mainloop() #Runs the program
Replace your Start() function with the following code:
def Start():
time_left = (50)
Stop.config (state = ACTIVE)
timer = Label (root, text = time_left)
timer.pack()
def update(time_left):
timer['text'] = time_left
if time_left > 0:
root.after(1000, update, time_left-1)
update(time_left)
After you create your label, the program calls a function called update, which sets the text of the timer label to time_left. It will then call root.after if time_left is greater than 0, and it passes time_left -1 back into the update function. This will make the timer countdown until it reaches 0.
The reason the timer Label isn't being shown is because the display is never given a chance to update. To fix that, try using the Start() function shown below which calls the universal widget method update_idletasks() to update it after it's been changed.
def Start():
time_left = 50
Stop.config(state=ACTIVE)
timer = Label(root, text=time_left)
timer.pack()
for i in range(50):
timer.config(text=time_left)
time_left -= 1
root.update_idletasks() # Update display.
root.after(1000) # Pause for 1000 milliseconds (1 second).
i want to make a notifying application in python using tkinter.
i want to check the system time if it matches the time from database time field of any row a window show flash on and off some specific number of times like danger warning lights.after the flashes finished those number of times a window should come showing about the events/scheduled that are to notified to the user.
i have tried to write the code but it makes the window appear only once.
i have tried using the root.after method of tkinter but dont know how to implement the requirements i want in the application.
#repeatedly checking if system time matched any teachers scedule time--------------------------------
def repeatedquery():
def alertmsg():
for j in range (4):
newteacheradd.withdraw()
messagewindow = Toplevel()
#to come out press alt+escape
messagewindow.wm_attributes("-fullscreen", 1)
messagewindow.title("Notification")
msgflash = Label(messagewindow, text='Notice', bg="#1f618d", fg='white', font=("Verdana", 28, 'bold'),
height=5,width=40, relief=RAISED)
msgflash.place(x=150, y=300)
print ("hjgj")
time.sleep(10)
messagewindow.after(15000, messagewindow.withdraw)
messagewindow.mainloop()
def showMesagewin():
newteacheradd.withdraw()
global messagewindow
messagewindow = Toplevel()
# Covers whole screen to come out press Alt + Esc
messagewindow.wm_attributes("-fullscreen", 1)
messagewindow.title("Notification Screen")
tt = '{:3}'.format(str(i[0])) + ' {:15}'.format(str(i[1])) + ' {:15}'.format(
str(i[2])) + ' {:15}'.format(str(i[3])) + '\n'
msg = 'YOUR LECTURE/PRAC DETAILS \n\n'+" "+tt
# to place message at centre
msgflash = Label(messagewindow, text=msg, bg="#1f618d",fg='white', font=("Verdana", 28,'bold'),height=5,relief = RAISED)
msgflash.place(x=250, y=300)
#Bell rings ___________________________________________________________________________________________
pygame.init()
pygame.mixer.init()
sounda = pygame.mixer.Sound("bell.wav")
sounda.play()
time.sleep(5)
#Belll rings____________________________________________________________________________________________
messagewindow.after(5000, messagewindow.withdraw)
# schedule closing of showMesagewin event in 5 seconds
messagewindow.mainloop()
currentDT = datetime.datetime.now()
t=currentDT.strftime("%H")
conn = sq.connect("Teacher.db")
curr = conn.cursor()
tid = __userip.get()
day2 = datetime.datetime.now()
day3 = day2.strftime("%A")
curr.execute("select Time,Subject,Lecture_prac,Venue from "+day3+" where Teacher_ID=?", (tid,))
sc = curr.fetchall()
t1=0
for i in sc:
if (t == i[0]):
alertmsg()
print ('gbhj')
showMesagewin()
newteacheradd.after(1000,repeatedquery)
#-------------------------------------------------------------------------------------------------
repeatedquery()
Edited Code
#repeatedly checking if system time matched any teachers scedule time--------------------------------
from tkinter import *
import datetime
import time
def mainwin():
newteacherappend=Tk()
i=[]
i.append(2)
i.append('Phy')
i.append('L')
i.append('301')
def repeatedquery():
def alertmsg():
for j in range (4):
newteacherappend.withdraw()
messagewindow = Toplevel()
# Covers whole screen to come out press Alt + Esc
messagewindow.wm_attributes("-fullscreen", 1)
messagewindow.title("Notification")
msgflash = Label(messagewindow, text='Notice', bg="#1f618d", fg='white', font=("Verdana", 28, 'bold'),
height=5,width=40, relief=RAISED)
msgflash.place(x=150, y=300)
print ("hjgj")
time.sleep(5)
messagewindow.after(5000, messagewindow.withdraw)
messagewindow.mainloop()
def showMesagewin():
newteacherappend.withdraw()
global messagewindow
messagewindow = Toplevel()
# Covers whole screen to come out press Alt + Esc
messagewindow.wm_attributes("-fullscreen", 1)
messagewindow.title("Notification Screen")
tt = '{:3}'.format(str(i[0])) + ' {:15}'.format(str(i[1])) + ' {:15}'.format(
str(i[2])) + ' {:15}'.format(str(i[3])) + '\n'
msg = 'YOUR LECTURE/PRAC DETAILS \n\n'+" "+tt
# to place message at centre
msgflash = Label(messagewindow, text=msg, bg="#1f618d",fg='white', font=("Verdana", 28,'bold'),height=5,relief = RAISED)
msgflash.place(x=250, y=300)
messagewindow.after(5000, messagewindow.withdraw)
# schedule closing of showMesagewin event in 5 seconds
messagewindow.mainloop()
currentDT = datetime.datetime.now()
t=currentDT.strftime("%H")
t=2
if (t == i[0]):
alertmsg()
print ('gbhj')
showMesagewin()
newteacherappend.after(1000,repeatedquery)
repeatedquery()
newteacherappend.mainloop()
mainwin()
I made code which use after without sleep to display flashing messages - first after after 5 seconds, second after 15 second. And it has only one mainloop().
More information in code
import tkinter as tk
import datetime
# --- functions ----
# function which creates window with message
def message_start(text):
global repeates
global message_window
global message_label
repeates = 3 # how many times change background color
# create window with messages
message_window = tk.Toplevel()
message_label = tk.Label(message_window, text=text, bg='red')
message_label.pack()
# update window after 500ms
root.after(500, message_update)
# function which changes background in displayed window
def message_update():
global message_window
global repeates
if repeates > 0:
repeates -= 1
if message_label['bg'] == 'red':
message_label['bg'] = 'green'
else:
message_label['bg'] = 'red'
# update window after 500ms
root.after(500, message_update)
else:
# close window
message_window.destroy()
# inform `check_time` that window is not busy
message_window = None
# loop which updates current time and checks which message it has to display
def check_time():
# display current time
current_time = datetime.datetime.now()
root_label_time['text'] = current_time.strftime('%Y.%m.%d %H:%M:%S')
# check if there is message to display
for message in messages:
if current_time >= message['start']: # it is time to display message
if message['state'] == 'waiting': # message is not displayed at this moment
if message_window is None: # window is not busy
message['state'] = 'displayed' # don't display it again
message_start(message['text']) # display message
# update time after 1000ms (1s)
root.after(1000, check_time)
# --- main ---
messages = [
{
'text': 'Time for coffee',
'start': datetime.datetime.now() + datetime.timedelta(seconds=5),
'state': 'waiting',
},
{
'text': 'Back to work',
'start': datetime.datetime.now() + datetime.timedelta(seconds=15),
'state': 'waiting',
},
]
message_window = None
repeates = 3
# ---
root = tk.Tk()
# label with current time
root_label_time = tk.Label(root, text='- wait -')
root_label_time.pack()
# label with sheduler
root_label_sheduler = tk.Label(root)
root_label_sheduler.pack()
# displa messages in sheduler
for message in messages:
root_label_sheduler['text'] += "\n" + message['start'].strftime('%Y.%m.%d %H:%M:%S ') + message['text']
# start displaying time
check_time()
root.mainloop()
I'm using trying to use python with an ultrasonic sensor to measure distance, and then update a tkinter label with the distance value every second. However, I'm having problems; it will run for a while, anything from a couple of seconds up to a few minutes, then freeze.
Here is my code:
from tkinter import *
import RPi.GPIO as GPIO
import time
GPIO.setmode(GPIO.BCM)
GPIO_TRIGGER_X = 4
GPIO_ECHO_X = 27
GPIO.setup(GPIO_TRIGGER_X, GPIO.OUT)
GPIO.setup(GPIO_ECHO_X, GPIO.IN)
def distanceX():
GPIO.output(GPIO_TRIGGER_X, True)
time.sleep(0.0001)
GPIO.output(GPIO_TRIGGER_X, False)
StartTime = time.time()
StopTime = time.time()
while GPIO.input(GPIO_ECHO_X) == 0:
StartTime = time.time()
while GPIO.input(GPIO_ECHO_X) == 1:
StopTime = time.time()
TimeElapsed = StopTime - StartTime
distance = (TimeElapsed * 34300) / 2
return distance
def updateDistance():
dX = distanceX()
print(dX)
lengthValue.configure(text=dX)
root.after(1000, updateDistance)
root = Tk()
root.geometry("200x100")
root.tk_setPalette(background="white", foreground="black")
lengthName = Label(root, text = "Length:")
lengthValue = Label(root, text="start")
lengthName.grid(row=1, column=1)
lengthValue.grid(row=1, column=2)
updateDistance()
root.mainloop()
I have tried running distanceX() alone in a separate script just printing out the values, that works fine. I've also tried the running the script without distanceX() like this:
dX = 0
def updateDistance():
global dX
print(dX)
lengthValue.configure(text=dX)
dX += 1
root.after(1000, updateDistance)
..and that also works fine.
Any ideas?
Apologies in advance if I've left any needed info out, this is my first go at python and tkinter...
Tkinter is single threaded. Your while loop in function distanceX blocks the main thread until it receives a True value and continues with the rest of the function. That's why you are experiencing freezes.
Try run the below:
from tkinter import *
import time
root = Tk()
flag = True
def something():
global flag
while flag:
print ("Hello World")
time.sleep(1)
def set_flag():
global flag
flag = False
something()
root.after(2000,set_flag)
root.mainloop()
And you will see your Tk window won't even pop up due to While loop blocking the main thread.
To solve this, you need to thread your distanceX() function. Something like:
from tkinter import *
import threading, time
root = Tk()
flag = True
def something():
global flag
while flag:
print ("Hello world")
time.sleep(1)
def set_flag():
global flag
flag = False
t = threading.Thread(target=something)
t.start()
root.after(2000,set_flag)
root.mainloop()
You can read more about threading in here.
Turns out the problem was in fact the two while loops in distanceX(). Added a timeout to both and all is well. Working code:
from tkinter import *
import RPi.GPIO as GPIO
import threading, time
GPIO.setmode(GPIO.BCM)
GPIO_TRIGGER_X = 4
GPIO_ECHO_X = 27
GPIO.setup(GPIO_TRIGGER_X, GPIO.OUT)
GPIO.setup(GPIO_ECHO_X, GPIO.IN)
def distanceX():
while True:
timeout = time.time() + 0.1
GPIO.output(GPIO_TRIGGER_X, True)
time.sleep(0.0001)
GPIO.output(GPIO_TRIGGER_X, False)
StartTime = time.time()
StopTime = time.time()
while GPIO.input(GPIO_ECHO_X) == 0:
StartTime = time.time()
if time.time() > timeout:
break
while GPIO.input(GPIO_ECHO_X) == 1:
StopTime = time.time()
if time.time() > timeout:
break
TimeElapsed = StopTime - StartTime
distance = (TimeElapsed * 34300) / 2
print(distance)
lengthValue.configure(text=distance)
time.sleep(1)
def check():
print("All good")
root = Tk()
root.geometry("200x100")
root.tk_setPalette(background="white", foreground="black")
lengthName = Label(root, text = "Length:")
lengthValue = Label(root, text="start")
button = Button(root, text="Check", command=check)
lengthName.grid(row=1, column=1)
lengthValue.grid(row=1, column=2)
button.grid(row=2, column=1)
t1 = threading.Thread(target=distanceX)
t1.start()
root.mainloop()
I have a problem using lambda: ... in my program. As I don't want my TkInter GUI to execute the functions automatically, I am using lambda. Problem is though that for Button3 it makes my program crash and I have no idea why. Without lambda it works absolutely fine. Here is my code:
import ogr, osr, sys, os
import psycopg2
import ppygis
from datetime import datetime, date
import time
import re
from Tkinter import *
import tkFileDialog
from tkFileDialog import askopenfilename # Open dialog box
from tkMessageBox import showerror
class trip_calculator:
def __init__(self):
global root
root = Tk()
def open_file_dialog():
returned_values = {}
returned_values['filename'] = askopenfilename()
Label(root, text= returned_values.get('filename')[52:] + ' selected').grid(row=2)
filepath = returned_values.get('filename')
#OPEN GPX DRIVER
driver = ogr.GetDriverByName('GPX')
datasource = driver.Open(filepath)
if datasource is None:
print 'not open'
else:
print 'open'
#GEOMETRY
datasource_layer = datasource.GetLayer(2)
#GRAB TIMESTAMPS, ELEVATION, CADENCE ETC.
datasource_layer2 = datasource.GetLayer(4)
#GRAB GEOMETRY INFORMATION AND TRANSFORM TO UTM
datasource_feature = datasource_layer.GetNextFeature()
geoSR = osr.SpatialReference()
geoSR.ImportFromEPSG(4326)
utmSR = osr.SpatialReference()
utmSR.ImportFromEPSG(32633)
coordTrans = osr.CoordinateTransformation(geoSR, utmSR)
geom = datasource_feature.GetGeometryRef()
geom1 = geom.Simplify(0)
geom.Transform(coordTrans)
geom1.Transform(coordTrans)
Label(root, text= 'geometries transformed successfully').grid(row=2, column=5)
#
# This is where the crash of Python occurs,
# `lambda: calculation(...)` won't start.
# It crashes at `features = iter(datasource_layer2)`
#
self.button3 = Button(root, text='calculate attributes', command=lambda:calculation(self,geom1,datasource_layer2)).grid(row=10, column=10, pady=10, padx=10)
def quit_me():
root.quit()
def calculation(self, geom1, datasource_layer2):
#NET AND GROSS TIME CALCULATION
timestamps_net = []
timestamps_net_helper = []
timestamps_elapsed = []
elevation_helper = []
print datasource_layer2
features = iter(datasource_layer2)
next(features)
for feature in features:
if len(timestamps_net_helper) == 2:
timestamps_net_helper = timestamps_net_helper[-1:]
timestamp = feature.GetField(4)
elevation = feature.GetField(3)
elevation_helper.append(elevation)
timestamp_stripped = timestamp[:-3]
day = timestamp[:-11]
#FOR GROSS CALCULATION
timestamps_elapsed.append(timestamp_stripped)
#FOR NET CALCULATION
timestamps_net_helper.append(timestamp_stripped)
if len(timestamps_net_helper) == 2:
#CALCULATE SECONDS BETWEEN
time_a = datetime.strptime(timestamps_net_helper[0], "%Y/%m/%d %H:%M:%S")
time_b = datetime.strptime(timestamps_net_helper[1], "%Y/%m/%d %H:%M:%S")
time_difference = time.mktime(time_b.timetuple()) - time.mktime(time_a.timetuple())
#IF SECONDS LESS THAN 20 BETWEEN GPS TIMESTAMP THEN ADD UP NET TIME
if time_difference < 20:
timestamps_net.append(time_difference)
seconds = sum(timestamps_net)
hours = seconds/60/60
time_length_net = time.strftime('%H:%M:%S', time.gmtime(seconds))
#CLIMB.....
positive_climb = []
negative_climb = []
for a, b in zip(elevation_helper, elevation_helper[1:]):
if a > 0.0 and b > 0.0:
if b > a:
positive_climb.append(b-a)
elif b == a:
pass
else:
negative_climb.append(a-b)
positive_climb = sum(positive_climb)
negative_climb = sum(negative_climb)
#GROSS (ELAPSED TIME)
start = datetime.strptime(timestamps_elapsed[0], "%Y/%m/%d %H:%M:%S")
end = datetime.strptime(timestamps_elapsed[-1], "%Y/%m/%d %H:%M:%S")
time_length = end - start
#LENGTH
length_km = float(geom1.Length()/1000)
#AVERAGE SPEED
avg_speed = (geom1.Length()/1000)/hours
#CREATE LINESTRING FOR PPYGIS AND OGR LINESTRING
myLine = ogr.Geometry(ogr.wkbLineString)
polyline = []
for z in range(geom1.GetPointCount()):
x = geom1.GetX(z)
y = geom1.GetY(z)
myLine.AddPoint(x, y)
point = ppygis.Point(x, y)
polyline.append(point)
myLine_ppy = ppygis.LineString(polyline)
Label(root, text= time_length).grid(row=10, column=5)
Label(root, text= length_km).grid(row=11, column=5)
Label(root, text= avg_speed).grid(row=12, column=5)
self.button1 = Button(root, text='browse', command= open_file_dialog).grid(row=0,pady=10, padx=25)
self.button2 = Button(root, text='close', command= quit_me).grid(row=3, pady=10, padx=25)
root.mainloop()
trip_calculator()
The error occuring is libc++abi.dylib: pure virtual method called but only using lambda in the command of button3. Any ideas how to fix this?
The problem is likely due to the fact that some of the arguments you have in thelambdaexpression -- namelygeom1anddatasource_layer2-- are variables local to the nestedopen_file_dialog() function and don't exist later when the button is pressed and it has returned.
A simple fix would be to make them attributes of the trip_calculator instance, by adding a self.datasource_layer2 = datasource_layer2andself.geom1 = geom1 statements somewhere before the function returns (or just assigning them toselfand referencing them that way everywhere else).