This question already has an answer here:
Clock with date and time in tkinter hangs
(1 answer)
Closed 8 months ago.
Digital clock is running based on system time. But after 10 seconds it stops.
Before this you can even see that the last 'tick' is 2 seconds instead of 1 second. That means it slows down somehow.
Why does it happen?
from tkinter import *
from tkinter import ttk
from time import strftime
import datetime
root = Tk()
root.title('Clock')
tabs = ttk.Notebook(root)
tabs.pack()
clock_tab = ttk.Frame(tabs)
timer_tab = ttk.Frame(tabs)
stopwatch_tab = ttk.Frame(tabs)
alarm_tab = ttk.Frame(tabs)
international_time_tab = ttk.Frame(tabs)
tabs.add(clock_tab, text='Clock')
tabs.add(timer_tab, text='Timer')
tabs.add(stopwatch_tab, text='Stopwatch')
tabs.add(alarm_tab, text='Alarm')
tabs.add(international_time_tab, text='International time')
def time():
time_str = datetime.datetime.now().strftime("%H:%M:%S")
date_str = datetime.datetime.now().strftime("%d.%m.%Y")
time_label.config(text = time_str)
time_label.after(1000, time)
date_label.config(text = date_str)
date_label.after(1000, time)
time_label = Label(root,font = ('calibri', 20))
time_label.pack()
date_label = Label(root,font = ('calibri', 15))
date_label.pack()
exit_btn = ttk.Button(
root,
text = 'Exit',
command = lambda: root.quit()
)
exit_btn.pack(fill = 'x')
def exit_func(event):
root.quit()
root.bind('<Return>', exit_func)
time()
mainloop()
Add this root.mainloop. Btw, when I typed time period, I didn't get any intellisense. There is no intellisense. But I can see intellisense in my example.
import sys
from tkinter import *
import time
def timing():
current_time = time.strftime("%H : %M : %S")
clock.config(text=current_time)
clock.after(200,timing)
root=Tk()
root.geometry("600x300")
clock=Label(root,font=("times",60,"bold"),bg="blue")
clock.grid(row=2,column=2,pady=25,padx=100)
timing()
root.mainloop()
Related
So Im trying to create a count down timer in the form of mm:ss and start counting down in an interval of 1 second when the button is being pressed. Im trying to make the timer show on the button too when counting down. This is what I have so far and I'm not sure what to do.
import tkinter as tk
root = tk.Tk()
monsterTimer = '00:02'
def converter(sec):
m, s = map(int, sec.split(":"))
sec = m * 60 + s
sec -= 1
m, s = divmod(sec, 60)
sec = (f'{m:02d}:{s:02d}')
if sec != '00:00':
sec = 'end'
root.after(1000, converter)
return sec
def update_btn_text():
btn_text.set(converter(monsterTimer))
btn_text = tk.StringVar()
btn_text.set(monsterTimer)
btn = tk.Button(root, textvariable=btn_text, command=lambda: update_btn_text())
btn.place(x=10, y=10)
root.mainloop()
Your solution was close, and using after instead of threads is the right way to go.
The first problem is that when you use root.after, you are calling converter but you aren't passing in an argument. You need to change the line to look like the following, which will call converter(sec) every second.
root.after(1000, converter, sec)
Another problem you have is that you are setting set to 'end' if it is not 00:00. You need to set it only if it is 00:00:
if sec == '00:00':
sec = 'end'
Third, you need to update the button text inside of converter, sometime before calling after:
...
btn_text.set(sec)
root.after(1000, converter, sec)
Finally, you don't need update_btn at all. It can be removed, and you can call converter from your button command.
btn = tk.Button(root, textvariable=btn_text, command=lambda: converter(monsterTimer))
Putting it all together, it looks like this:
import tkinter as tk
root = tk.Tk()
monsterTimer = '00:10'
def converter(sec):
m, s = map(int, sec.split(":"))
sec = m * 60 + s
sec -= 1
m, s = divmod(sec, 60)
sec = (f'{m:02d}:{s:02d}')
if sec == '00:00':
sec = 'end'
btn_text.set(sec)
if sec != "end":
root.after(1000, converter, sec)
btn_text = tk.StringVar()
btn_text.set(monsterTimer)
btn = tk.Button(root, textvariable=btn_text, command=lambda: converter(monsterTimer))
btn.place(x=10, y=10)
root.mainloop()
Try this code:
import tkinter as tk
import time
import threading
root = tk.Tk()
monsterTimer = '00:00'
run_tm = 5
def update_btn_text(sec):
while sec:
m, s = divmod(sec, 60)
m, s = str(m).zfill(2), str(s).zfill(2)
tm = f'{m}:{s}'
btn_text.set(tm)
time.sleep(1)
sec -= 1
btn_text.set("00:00")
def startThread(t):
th1 = threading.Thread(target=update_btn_text, args=(t, ))
th1.start()
btn_text = tk.StringVar()
btn_text.set(monsterTimer)
btn = tk.Button(root, textvariable=btn_text, command=lambda: startThread(run_tm))
btn.place(x=50, y=50)
root.mainloop()
I want to write an app that displays current Bitcoin price next to current time. I am new to python and tkinter and I don't know how to add the Bitcoin variable next to time.
import requests
btc = requests.get('https://api.coindesk.com/v1/bpi/currentprice.json')
btc_price = (btc.json()['bpi']['USD']['rate'])
from tkinter import *
from tkinter.ttk import *
from time import strftime
root = Tk()
root.title('Btc')
label = Label(root, font = ('arial', 40, 'bold'), background = 'white', foreground = 'black')
def time():
string = strftime('%H:%M:%S %p')
label.config(text = string)
label.after(1000, time)
label.pack(anchor = 'center')
time()
mainloop()
I can only get it to display time.
Hope this is what you wanted.
#imports
import requests
from tkinter import *
from tkinter.ttk import *
from time import strftime
#Canvas preparation
root = Tk()
root.title('Btc')
label = Label(root, font = ('arial', 40, 'bold'), background = 'white', foreground = 'black')
label2 = Label(root, font = ('arial', 40, 'bold'), background = 'white', foreground = 'black')
#Looper/Updater method
def time():
string = strftime('%H:%M:%S %p')
#value request
btc = requests.get('https://api.coindesk.com/v1/bpi/currentprice.json')
btc_price = (btc.json()['bpi']['USD']['rate']) # You might wanna keep the value updated, right?
#Assigning values to label for updating.
label.config(text = string)
label2.config(text=btc_price)
#recursive rendition loop
label.after(1000, time)
#Use the coordinate system as opposed to anchor system to place the values.
#Here I have taken LEFT side edge as reference, you might wanna change per aesthetic appeal.
label.pack(padx=5, pady=10, side=LEFT)
label2.pack(padx=5, pady=20, side=RIGHT)
#Recursive rendition call
time()
#Exhibit
mainloop()
So, I've made some code which has 2 functions: A clock and a countdown timer (simultaneously).
But, they show each other simultaneously as well, but what I need is only one of them at a time: For this example below, while the countdown timer starts at 60 seconds and goes to 0, it has to show on the screen, and when it reaches 0, switch back to the clock.
What is currently happening is both of them showing all the time, I just need to know how to specify something like an if countdown > 0, show countdown timer... if countdown = 0, show clock
Can anybody help me?
import tkinter as tk
from tkinter import *
import time
root = Tk()
root.attributes("-fullscreen", True)
root.config(cursor="none")
display = Label(root, font=('helvetica', 180, 'bold'), bg='black', fg='white')
display.pack(fill=BOTH, expand=1)
hora = 0
tempo = 60
def clock():
global hora
hora = time.strftime('%H:%M:%S')
display['text'] = hora
root.after(100, clock)
clock()
def countdown():
global tempo
display['text'] = ('{0:02d}:{1:02d}'.format(*divmod(tempo, 60)))
if tempo > 0:
tempo = tempo - 1
root.after(1000, countdown)
countdown()
root.mainloop()
If you use a single function then you won't have to worry about it fighting itself :)
import tkinter as tk
from tkinter import *
import time
root = Tk()
root.attributes("-fullscreen", True)
root.config(cursor="none")
display = Label(root, font=('helvetica', 180, 'bold'), bg='black', fg='white')
display.pack(fill=BOTH, expand=1)
tempo = 60
def tick():
global tempo
if tempo > 0:
# countdown mode
display['text'] = ('{0:02d}:{1:02d}'.format(*divmod(tempo, 60)))
tempo = tempo - 1
else:
# clock mode
hora = time.strftime('%H:%M:%S')
display['text'] = hora
root.after(1000, tick)
tick()
root.mainloop()
I have this problem in Python. Yesterday, I copied the Countdown Calendar code in Coding Projects with Python and added the 'events.txt'. I checked all the problem to make sure it work. But when I ran it, the text isn't show up. Here is how my documents are set up:
Here's the code:
from tkinter import Tk, Canvas
from datetime import date, datetime
def get_events():
list_events = []
with open('events.txt') as file:
for line in file:
line = line.rstrip('\n')
current_event = line.split('.')
event_date = datetime.strptime(current_event[1], '%d/%m/%y').date()
current_event[1] = event_date
list_events.append(current_event)
return list_events
def days_between_dates(date1, date2):
time_between = str(date1 - date2)
number_of_days = time_between.split(' ')
return number_of_days[0]
root = Tk()
c = Canvas(root, width=800, height=800, bg='black')
c.pack()
c.create_text(100, 50, anchor='w', fill='orange', \
font='Arial 28 bold underline', text='My Countdown Calendar')
events = get_events()
today = date.today()
vertical_space = 100
for event in events:
event_name = event[0]
days_until = days_between_dates(event[1], today)
display = 'It is %s days until %s' % (days_until, event_name)
c.create_text(100, vertical_space, anchor='w', fill='lightblue', \
font='Arial 28 bold', text=display)
I think there are a couple things.
current_event = line.split('.') - I believe this should be a comma, not a period.
Like somebody else has mentioned, if using PyCharm, you need to add root.mainloop() to the end of your file.
Make sure your text file doesn't have any additional lines at the end and there are no spaces between the events and the event dates - just a comma.
I found that this fixed my issues when working on this exercise.
you need root.mainloop() at the end of your code for it to run
I have designed a full-screen clock for my Raspberry Pi 3 Model B which runs on Raspbian but can also run on Windows. The whole point of the clock is to show the date, time, and a RSS feed on r/news (Reddit).
The news feed should stay on the screen for 5 seconds then change to the next one, and this process should go on forever until I exit. If I use sleep(), the clock stops. I have tried using threading, but it only works on the first loop, and then tries to show the next one, but returns to the previous one.
The clock and date work fine, it's just that I can't get the feed to stay on screen for 5 seconds and move on to the next one.
Code:
import sys
if sys.version_info[0] == 2:
from Tkinter import *
else:
from tkinter import *
from time import *
import datetime
import feedparser
root = Tk()
d = feedparser.parse('https://www.reddit.com/r/news/.rss')
def exitt():
sleep(3)
root.destroy()
time1 = ''
extra_time1 = ''
clock = Label(root, font=('calibri light', 150), bg='black', fg='white')
clock.pack(fill=BOTH, expand=1)
extra_clock = Label(root, font=('calibri light', 45), bg='black', fg='white')
extra_clock.pack(fill=BOTH, expand=1)
label_rss = Label(root, font=('calibri', 14), bg='black', fg='white')
label_rss.pack(fill=BOTH)
end = Button(root, text="Exit", font=('bold', 20), fg="white",
bg='black', bd=0, borderwidth=0, highlightthickness=0,
highlightcolor='black', command=lambda:exitt(), height=0, width=0)
end.pack(fill=BOTH)
def rssfeeds():
for post in d.entries:
RSSFEED = post.title
label_rss.config(text=RSSFEED)
#sleep(5) <-- To prevent glitches but to keep my point
#rssfeeds()
def tick():
global time1
time2 = strftime("%H:%M:%S")
if time2 != time1:
time1 = time2
clock.config(text=time2)
clock.after(1, tick)
def ticki():
global extra_time1
extra_time2 = strftime("%A, %d %B %Y")
if extra_time2 != extra_time1:
extra_time1 = extra_time2
extra_clock.config(text=extra_time2)
extra_clock.after(1, ticki)
tick()
ticki()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set() # <-- move focus to this widget
root.mainloop()
I have added the first few lines to make it easier to run this code if you are using Python 3 because feedparser can run on Python up to v.3.4.
To do what you want you need an "iterator", which is a type of object that can spit out one element at a time. For you I would recommend itertools.cycle, since it also loops back to the beginning after it's done. Remember in event driven programming (GUIs) you can't use a normal loop, you have to have an event fire the next action. The event you will use is set with after.
#!/usr/bin/env python
import sys
if sys.version_info[0] == 2:
import Tkinter as tk
else:
import tkinter as tk
from time import sleep, strftime
import datetime
import feedparser
from itertools import cycle
root = tk.Tk()
d = feedparser.parse('https://www.reddit.com/r/news/.rss')
post_list = cycle(d.entries)
def exitt():
sleep(3)
root.destroy()
time1 = ''
extra_time1 = ''
clock = tk.Label(root, font=('calibri light', 150), bg='black', fg='white')
clock.pack(fill=tk.BOTH, expand=1)
extra_clock = tk.Label(root, font=('calibri light', 45), bg='black', fg='white')
extra_clock.pack(fill=tk.BOTH, expand=1)
label_rss = tk.Label(root, font=('calibri', 14), bg='black', fg='white')
label_rss.pack(fill=tk.BOTH)
end = tk.Button(root, text="Exit", font=('bold', 20), fg="white",
bg='black', bd=0, borderwidth=0, highlightthickness=0,
highlightcolor='black', command=lambda:exitt(), height=0, width=0)
end.pack(fill=tk.BOTH)
def rssfeeds():
post = next(post_list)
RSSFEED = post.title
label_rss.config(text=RSSFEED)
root.after(5000, rssfeeds) # call this method again in 5 seconds
rssfeeds()
def tick():
global time1
time2 = strftime("%H:%M:%S")
if time2 != time1:
time1 = time2
clock.config(text=time2)
clock.after(1000, tick)
def ticki():
global extra_time1
extra_time2 = strftime("%A, %d %B %Y")
if extra_time2 != extra_time1:
extra_time1 = extra_time2
extra_clock.config(text=extra_time2)
extra_clock.after(1000, ticki)
tick()
ticki()
w, h = root.winfo_screenwidth(), root.winfo_screenheight()
root.overrideredirect(1)
root.geometry("%dx%d+0+0" % (w, h))
root.focus_set() # <-- move focus to this widget
root.mainloop()
Some more things to note:
use 4 spaces for indenting (read PEP8 for more style recommendations)
Do not use wildcard imports (from module import *), they lead to bugs and are also against PEP8.
Use a shebang always, but especially on linux systems.
move to classes and OOP as soon as you can to clean up the code.