Python Forum
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Alarm Clock [tkinter]
#1
Hiya! I'm trying to make an alarm clock as homework however I keep getting this strange error:
Error:
Traceback (most recent call last): File "C:\Users\RPC-K\OneDrive\Documents\PY.LESSON FLIES\HOMEWORK15\IDK.py", line 43, in <module> label1 = root.Label(root, image=bg) File "C:\Program Files\Python311\Lib\tkinter\__init__.py", line 2410, in __getattr__ return getattr(self.tk, attr) AttributeError: '_tkinter.tkapp' object has no attribute 'Label'
My code used to work as intended but now a blank white tkinter window is all tat appears.
I tried requesting assistance from my teacher but she is just as confused as I am so she left me to it.
Here is my code:
# Import Required Library
from tkinter import *
import datetime
import time
import winsound
from threading import *
 
# Create Object
root = Tk()
 
# Set geometry
root.geometry("400x200")
 
# Use Threading
def Threading():
	t1=Thread(target=alarm)
	t1.start()
 
def alarm():
	# Infinite Loop
	while True:
		# Set Alarm 
		set_alarm_time = f"{hour.get()}:{minute.get()}:{second.get()}"
 
		# Wait for one seconds
		time.sleep(1)
 
		# Get current time
		current_time = datetime.datetime.now().strftime("%H:%M:%S")
		print(current_time,set_alarm_time)
 
		# Check whether set alarm is equal to current time or not
		if current_time == set_alarm_time:
			print("Time to Wake up")
			# Playing sound
			winsound.PlaySound("sound.wav",winsound.SND_ASYNC)

bg = PhotoImage(file = r"C:\Users\RPC-K\Downloads\giphy.gif")

# Set the label's background color to match your application's 

# Show image using label 
label1 = root.Label(root, image=bg) 
label1.place(x = 530, y = 300) 
  
# Add text 
label2 = root.Label(root, text="Welcome", 
               bg = "#88cffa") 
  
label2.pack(pady = 50) 
  
# Create Frame 
frame1 = root.Frame(root, bg="#88cffa") 
frame1.pack(pady = 20)

# Add Labels, Frame, Button, Optionmenus
Label(root,text="Khanam's Alarm Clock",font=("Wistful 90 bold"),fg="Light Blue").pack(pady=10)
root.wm_attributes("-transparentcolor", "white")

Label(root,text="Set Time",font=("Wistful 50 bold"),fg="Dark blue").pack()
root.wm_attributes("-transparentcolor", "white")

label_instance = Label(root)  # Create an instance of the Label class
label_instance.configure(bg=root.cget("bg"))  # Call configure on the instance
 
frame = Frame(root)
frame.pack()
 
hour = StringVar(root)
hours = ('00', '01', '02', '03', '04', '05', '06', '07',
		'08', '09', '10', '11', '12', '13', '14', '15',
		'16', '17', '18', '19', '20', '21', '22', '23', '24'
		)
hour.set(hours[0])
 
hrs = OptionMenu(frame, hour, *hours)
hrs.pack(side=LEFT)
 
minute = StringVar(root)
minutes = ('00', '01', '02', '03', '04', '05', '06', '07',
		'08', '09', '10', '11', '12', '13', '14', '15',
		'16', '17', '18', '19', '20', '21', '22', '23',
		'24', '25', '26', '27', '28', '29', '30', '31',
		'32', '33', '34', '35', '36', '37', '38', '39',
		'40', '41', '42', '43', '44', '45', '46', '47',
		'48', '49', '50', '51', '52', '53', '54', '55',
		'56', '57', '58', '59', '60')
minute.set(minutes[0])
 
mins = OptionMenu(frame, minute, *minutes)
mins.pack(side=LEFT)
 
second = StringVar(root)
seconds = ('00', '01', '02', '03', '04', '05', '06', '07',
		'08', '09', '10', '11', '12', '13', '14', '15',
		'16', '17', '18', '19', '20', '21', '22', '23',
		'24', '25', '26', '27', '28', '29', '30', '31',
		'32', '33', '34', '35', '36', '37', '38', '39',
		'40', '41', '42', '43', '44', '45', '46', '47',
		'48', '49', '50', '51', '52', '53', '54', '55',
		'56', '57', '58', '59', '60')
second.set(seconds[0])
 
secs = OptionMenu(frame, second, *seconds)
secs.pack(side=LEFT)
 
Button(root,text="Set Alarm",font=("Comfortaa 15"),command=Threading).pack(pady=20)

# Create a canvas widget
canvas=Canvas(root, width=1000, height=500)
canvas.configure(background='black')

canvas.pack()

# Create an oval or ball in the canvas widget
ball=canvas.create_oval(10,10,50,50, fill="lavender")

# Move the ball
xspeed=yspeed=10

def move_ball():
   global xspeed, yspeed

   canvas.move(ball, xspeed, yspeed)
   (leftpos, toppos, rightpos, bottompos)=canvas.coords(ball)
   if leftpos <=0 or rightpos>=700:
      xspeed=-xspeed

   if toppos <=0 or bottompos >=350:
      yspeed=-yspeed

   canvas.after(100, move_ball)

canvas.after(1000, move_ball)

bounce = Tk.Label(parent, image=background_image)
bounce.place(x=0, y=0, relwidth=1, relheight=1)

# Execute Tkinter
root.mainloop()
All help would be greatly appreciated! Thanks! - moon
JUST A FRIENDLY REMINDER, I AM INFACT A YOUNG CHILD SO PLEASE FORGIVE ME IF I LACK OF ANY KNOWLEDGE THAT MAY SEEM OBVIOUS...I AM STILL DEVELOPING MY SKILLS IN PYTHON - YOURS SINCERELY, Moon
😋
Reply
#2
Label is not an attribute of root, it is a function in tkinter. Instead of:
label1 = root.Label(root, image=bg) 
use this:
label1 = Label(root, image=bg) 
But you really shouldn't do this:
from tkinter import *
from threading import *
Wildcard imports make it difficult to track where variables are defined. If I do this:
import tkinter as tk
root = tk.Tk()
It is easy to see that Tk() is a function defined in tkinter. Wildcard imports can also lead to replacing functions and variables defined in your code with functions and variables defined in the imported module. This happens without any warning, and the resulting behavior can be difficult to debug. Interestingly, tkinter takes advantage of this with the ttk package.
from tkinter import *
from tkinter.ttk import *
Adding "from tkinter.ttk import *" to an old tkinter program updates all (nearly all) of the widgets with newer widgets that support styling.

A few comments about your program:

Once you fix the Label problem you'll discover that you cannot use place() and pack() together. This is fine, because you should not be using place() to layout widgets and you shouldn't be using geometry() to set the size of the window. Learn how pack() and grid() work and use them to not only position widgets in your window but set the size of the window. This will allow easy resizing.

This is way too much typing:
seconds= ["00", "01"..."60"]
Instead do something like this:
seconds= [f"{x:<02}" for x in range(0, 61)]
And once you have seconds, use slicing to define hours.
hours = seconds[:25]
And instead of defining minutes, reuse seconds.

When you find yourself doing a lot of repetitive typing, there's a good chance that Python provides a shortcut. Python code should be terse.

I congratulate you for seeing the benefit of tkinter variables, but you can define them more efficiently. Instead of this:
hour = StringVar(root)
hours = ('00', '01', '02', '03', '04', '05', '06', '07',
        '08', '09', '10', '11', '12', '13', '14', '15',
        '16', '17', '18', '19', '20', '21', '22', '23', '24'
        )
hour.set(hours[0])
  
hrs = OptionMenu(frame, hour, *hours)
hrs.pack(side=LEFT)
  
minute = StringVar(root)
minutes = ('00', '01', '02', '03', '04', '05', '06', '07',
        '08', '09', '10', '11', '12', '13', '14', '15',
        '16', '17', '18', '19', '20', '21', '22', '23',
        '24', '25', '26', '27', '28', '29', '30', '31',
        '32', '33', '34', '35', '36', '37', '38', '39',
        '40', '41', '42', '43', '44', '45', '46', '47',
        '48', '49', '50', '51', '52', '53', '54', '55',
        '56', '57', '58', '59', '60')
minute.set(minutes[0])
  
mins = OptionMenu(frame, minute, *minutes)
mins.pack(side=LEFT)
  
second = StringVar(root)
seconds = ('00', '01', '02', '03', '04', '05', '06', '07',
        '08', '09', '10', '11', '12', '13', '14', '15',
        '16', '17', '18', '19', '20', '21', '22', '23',
        '24', '25', '26', '27', '28', '29', '30', '31',
        '32', '33', '34', '35', '36', '37', '38', '39',
        '40', '41', '42', '43', '44', '45', '46', '47',
        '48', '49', '50', '51', '52', '53', '54', '55',
        '56', '57', '58', '59', '60')
second.set(seconds[0])
  
secs = OptionMenu(frame, second, *seconds)
secs.pack(side=LEFT)
Do this
import tkinter as tk

seconds = [f"{x:<02}" for x in range(0, 61)]]
hours = seconds[:25]

root = tk.Tk()
...
frame = tk.Frame(root)

hour = tk.StringVar(root, hours[0])
tk.OptionMenu(frame, hour, *hours).pack(side=tk.LEFT)

minute = tk.StringVar(root, seconds[0])
tk.OptionMenu(frame, minute, *seconds).pack(side=tk.LEFT)

second = tk.StringVar(root, seconds[0])
tk.OptionMenu(frame, second, *seconds).pack(side=tk.LEFT)
You don't need to make a variable for the hour, minute or second OptionMenus. The variable is only ever used by the pack() function call. Instead of making a variable for a single use, you can chain the OptionMenu() call and the pack() call.

There is no need for threading in this program. In tkinter use after(delay_in_ms, function) to periodically call a function. You could use this to call the alarm function once a second to check if it is time to play the alarm sound.
def alarm():
    """Check alarm."""
    if f"{hour.get()}:{minute.get()}:{second.get()}" == datetime.now().strftime("%H:%M:%S"):
        winsound.PlaySound("sound.wav",winsound.SND_ASYNC)
    root.after(1000, alarm)  # Call alarm a second from now.
moon likes this post
Reply
#3
Hi there!
I would like to thankyou so much for sending me all this valuable information. I have managed to solve the label issue and my image is being displayed as intended. However, all of the other aspects of my prgram have entirely disappeared and aside from the image, the tkinter canvas is blank. I also keep recieving a really long error:
Error:
Traceback (most recent call last): File "C:/Users/RPC-K/OneDrive/Documents/PY.LESSON FLIES/HOMEWORK18/new.py", line 31, in <module> label2 = Label(root, text="Welcome", File "C:\Program Files\Python311\Lib\tkinter\ttk.py", line 729, in __init__ Widget.__init__(self, master, "ttk::label", kw) File "C:\Program Files\Python311\Lib\tkinter\ttk.py", line 527, in __init__ tkinter.Widget.__init__(self, master, widgetname, kw=kw) File "C:\Program Files\Python311\Lib\tkinter\__init__.py", line 2628, in __init__ self.tk.call( _tkinter.TclError: unknown option "-bg"
In my current code you will see how I have implemented the code you had provided and used it to replace my mistakes:
# Import Required Library
from tkinter import *
from tkinter.ttk import *
import datetime
import time
import winsound

  
# Create Object
root = Tk()
  
# Set geometry
root.geometry("400x200")

def alarm():
    """Check alarm."""
    if f"{hour.get()}:{minute.get()}:{second.get()}" == datetime.now().strftime("%H:%M:%S"):
        winsound.PlaySound("sound.wav",winsound.SND_ASYNC)
    root.after(1000, alarm)  # Call alarm a second from now.

 
bg = PhotoImage(file = r"C:\Users\RPC-K\Downloads\giphy.gif")
 
# Set the label's background color to match your application's 
 
# Show image using label 
label1 = Label(root, image=bg)  
label1.place(x = 530, y = 300) 
   
# Add text 
label2 = Label(root, text="Welcome", 
               bg = "#88cffa") 
   
label2.pack(pady = 50) 
   
# Create Frame 
frame1 = root.Frame(root, bg="#88cffa") 
frame1.pack(pady = 20)
 
# Add Labels, Frame, Button, Optionmenus
Label(root,text="Khanam's Alarm Clock",font=("Wistful 90 bold"),fg="Light Blue").pack(pady=10)
root.wm_attributes("-transparentcolor", "white")
 
Label(root,text="Set Time",font=("Wistful 50 bold"),fg="Dark blue").pack()
root.wm_attributes("-transparentcolor", "white")
 
label_instance = Label(root)  # Create an instance of the Label class
label_instance.configure(bg=root.cget("bg"))  # Call configure on the instance
  
frame = tk.Frame(root)
 
hour = tk.StringVar(root, hours[0])
tk.OptionMenu(frame, hour, *hours).pack(side=tk.LEFT)
 
minute = tk.StringVar(root, seconds[0])
tk.OptionMenu(frame, minute, *seconds).pack(side=tk.LEFT)
 
second = tk.StringVar(root, seconds[0])
tk.OptionMenu(frame, second, *seconds).pack(side=tk.LEFT)
 
# Execute Tkinter
root.mainloop()
All of your help has been and will continue to be appreciated by me as much as I can. Thankyou for your patience and understanding...
JUST A FRIENDLY REMINDER, I AM INFACT A YOUNG CHILD SO PLEASE FORGIVE ME IF I LACK OF ANY KNOWLEDGE THAT MAY SEEM OBVIOUS...I AM STILL DEVELOPING MY SKILLS IN PYTHON - YOURS SINCERELY, Moon
😋
Reply
#4
That is a really short error.
Error:
_tkinter.TclError: unknown option "-bg"
It happens because of this line of code in your program.
Error:
File "C:/Users/RPC-K/OneDrive/Documents/PY.LESSON FLIES/HOMEWORK18/new.py", line 31, in <module> label2 = Label(root, text="Welcome",
The complete line from your program is this:
label2 = Label(root, text="Welcome", 
               bg = "#88cffa") 
Looks like Label does not have a "bg" option. Let's look at the docs:

https://tcl.tk/man/tcl8.6/TkCmd/label.htm
Quote:NAME
label — Create and manipulate 'label' non-interactive text or image widgets
SYNOPSIS
STANDARD OPTIONS
-activebackground, activeBackground, Foreground
-activeforeground, activeForeground, Background
-anchor, anchor, Anchor
-background or -bg, background, Background
Hmmm, looks like bg should be fine. Take another look at the traceback on that error message.
Error:
File "C:\Program Files\Python311\Lib\tkinter\ttk.py", line 729, in __init__ Widget.__init__(self, master, "ttk::label", kw)
Oh, Label is not a tkinter label, it is a ttk label. Remember when I warned you about the dangers of wildcard imports? About how wildcard imports can result in overwriting variables and functions? That is happening here in your program. tkinter has a Label class, and ttk has a Label class. When you do imports like this:
from tkinter import *
from tkinter.ttk import *
The Label from ttk replaces the label in tkinter. This is actually by design with the ttk library. The designers of the library wanted it to be a drop-in update to tkinter, making it simple to update old tkinter programs by adding one line. Neat sounding idea, but not a good idea in practice. Lets look at the ttk documentation.

https://tcl.tk/man/tcl8.6/TkCmd/ttk_label.htm
Quote:NAME
ttk::label — Display a text string and/or image
SYNOPSIS
DESCRIPTION
...
WIDGET-SPECIFIC OPTIONS
-anchor, anchor, Anchor
-background, frameColor, FrameColor
bg is not an option for ttk.Label
Reply
#5
Hi again! thankyou for letting me know about this. I have taken a look at your comments and if I am being honest, I sort of lack an understanding of what is actually going on. Could you please kindly explain what I need to do or implement in order to fix these issues?
Thankyou so so much!
Yours Sicerely, moon... Heart
JUST A FRIENDLY REMINDER, I AM INFACT A YOUNG CHILD SO PLEASE FORGIVE ME IF I LACK OF ANY KNOWLEDGE THAT MAY SEEM OBVIOUS...I AM STILL DEVELOPING MY SKILLS IN PYTHON - YOURS SINCERELY, Moon
😋
Reply
#6
I think you should start with something simpler. Make a window with a label and a button. Put the label above the button. Put the label left of the button. Adjust the margins around the label and the button. Change the background color for the entire window. Master one thing at a time.
moon likes this post
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  World Clock syntax error OscarBoots 1 712 May-03-2024, 05:20 AM
Last Post: snippsat
  Alarm system with state, class, enum. Frankduc 0 1,608 May-04-2022, 01:26 PM
Last Post: Frankduc
  simulation of alarm system Frankduc 6 2,377 Apr-21-2022, 03:45 PM
Last Post: Frankduc
  Module 'time' has no attribute 'clock' Sophie 4 4,112 Jan-25-2022, 08:05 PM
Last Post: Sophie
  Clock\time calculation script Drone4four 3 1,965 Jan-21-2022, 03:44 PM
Last Post: ibreeden
  time.clock not functioning Oldman45 3 3,286 Apr-07-2021, 08:51 AM
Last Post: Oldman45
  Cannot use function with timer/clock theangryprogrammer 1 3,622 Jan-22-2019, 04:22 PM
Last Post: Larz60+
  Problem with 'Clock' functionality panoss 2 3,933 May-17-2017, 07:03 PM
Last Post: snippsat
  Problems with Interrupts/ callback functions in Python for an Alarm Clock project Henry1 1 5,299 Dec-16-2016, 10:17 PM
Last Post: nilamo

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020