How to specify Tkinter correct label? - python

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()

Related

Move window from "second plan/background(minimized)" to the "first plan/active window"

Sorry for my english guys,
I didn't find the correct words to explain this,
I developed a pomodoro clock, and I read the tkinter documentation, but I don't find how can I move the window to front(active window), to the first plan when the timer finish.
for example, if I minimize the app, I need when the time finish, It show on my screen.
could some one help me please? thank you!!
import tkinter as tk
import os
from tkinter.font import NORMAL
# ---------------------------- CONSTANTS ------------------------------- #
PINK = "#e2979c"
RED = "#e7305b"
GREEN = "#9bdeac"
YELLOW = "#f7f5dd"
FONT_NAME = "Courier"
WORK_MIN = 25
SHORT_BREAK_MIN = 5
LONG_BREAK_MIN = 20
PATH = os.path.dirname(__file__)
reps = 0
# ---------------------------- TIMER RESET ------------------------------- #
def reset():
global loop, reps
lbl_mark.config(text='')
lbl1.config(text='Timer', fg=GREEN)
canvas.itemconfig(timer, text="00:00")
btn_start.config(state=NORMAL)
myapp.after_cancel(loop)
reps = 0
# ---------------------------- TIMER MECHANISM ------------------------------- #
def start_counter():
global reps
reps += 1
btn_start.config(state=tk.DISABLED)
if reps != 0 and reps % 8 == 0:
lbl_mark.config(text='✔' * int(reps/2))
lbl1.config(text="Long Break", fg=RED)
counter(LONG_BREAK_MIN * 60)
elif reps %2 == 0:
lbl_mark.config(text='✔'* int(reps/2))
lbl1.config(text="Break", fg=PINK)
counter(SHORT_BREAK_MIN * 60)
else:
lbl1.config(text="Work", fg=GREEN)
counter(WORK_MIN * 60)
# ---------------------------- COUNTDOWN MECHANISM ------------------------------- #
def counter(count):
global loop
minutes = int(count / 60)
seconds = count % 60
if seconds < 10:
seconds = f"0{seconds}"
if minutes < 10:
minutes = f"0{minutes}"
canvas.itemconfig(timer, text=f'{minutes}:{seconds}')
if count > 0:
loop = myapp.after(1000, counter, count -1)
else:
start_counter()
# ---------------------------- UI SETUP ------------------------------- #
myapp = tk.Tk()
myapp.title("Pomodoro")
myapp.config(padx=100, pady=50, bg=YELLOW)
#timer label
lbl1 = tk.Label(text="Timer", font=(FONT_NAME, 35, 'bold'),fg=GREEN, bg=YELLOW)
lbl1.grid(column=1, row=0)
#tomato
canvas = tk.Canvas(width=200, height=224, bg=YELLOW, highlightthickness=0)
tomato = tk.PhotoImage(file=os.path.join(PATH,"tomato.png"))
canvas.create_image(100,112, image=tomato)
canvas.grid(column=1, row=1)
#text inside tomato
timer = canvas.create_text(102,130, text="00:00", fill="white", font=(FONT_NAME, 35, "bold"))
#button start
btn_start = tk.Button(text="Start", command=start_counter)
btn_start.grid(column=0, row=2)
#text mark
lbl_mark = tk.Label(font=(FONT_NAME, 14, 'bold'), fg=GREEN, bg=YELLOW)
lbl_mark.grid(column=1, row=3)
#button reset
btn_reset = tk.Button(text='Reset', command=reset)
btn_reset.grid(column=2, row=2)
myapp.mainloop()

Tkinter window stops updating randomly for no reason

I created a timer but for some reason the timer randomly stops updating until I click the tkinter window then it starts to update again. This happens about every minute or two. Here is my code:
from tkinter import *
from threading import Thread
tk = Tk()
tk.attributes('-alpha',1)
tk ['bg']='#302F2F'
tk.title('')
tk.wm_attributes('-topmost', 1) # put the window to front
def timer():
while True:
sleep(0.009)
...
#cut out all the stuff of creating the time but here is how i did it
label['text'] = (ftime2)
label['fg'] = colorfortext
label2['text'] = (ftime)
label2['fg'] = colorfortext
label3['text'] = (numberofworlds)
label3['fg'] = 'blue'
label = Label(tk, '', font=('Arial', 30),bg='#302F2F')
label.grid(columnspan=2)
label2 = Label(tk, '', font=('Arial', 30),bg='#302F2F')
label2.grid(columnspan=2)
label3 = Label(tk, '', font=('Arial', 30),bg='#302F2F')
label3.grid(columnspan=2)
timer_thread = Thread(target=timer)
timer_thread.start()
tk.mainloop()

Button isn't displaying the timer

I'm making a little game for my 4-year-old nephew. you plug two mice into the computer and try to press your button and I need the start button to turn into a timer. The problem is the button isn't displaying the time. It stops responding until the time is up and then displays "1". (keep in mind this is unfinished)
import tkinter
from tkinter import ttk
import time
score = 0
window = tkinter.Tk()
window.geometry("300x200")
def button1():
score = score - 1
def button2():
score = score + 1
def Start():
t = 30
while t > 0:
mins, secs = divmod(t, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
start.config(text=t)
print(timer, end="\r")
time.sleep(1)
t -= 1
start = ttk.Button( window, text = "Start", command = Start)
start.pack(padx= 2, pady = 1)
one = ttk.Button( window, text = "Player 1", command = button1)
one.pack(padx= 2, pady = 1)
two = ttk.Button( window, text = "Player 2", command = button2)
two.pack(padx= 2, pady = 1)
window.mainloop()
Here is an answer on the while loops indegestibility with the tkinter mainloop.
You could also solve this by running your start() function in its own thread:
import threading
def start():
t = 30
while t > 0:
mins, secs = divmod(t, 60)
timer = '{:02d}:{:02d}'.format(mins, secs)
start_button.config(text=t)
print(timer, end="\r")
time.sleep(1)
t -= 1
def start_in_thread():
thread = threading.Thread(target=start)
thread.daemon = True # forces thread to close when the tkinter mainloop is closed
thread.start()
start_button = ttk.Button(window, text="Start", command=start_in_thread)
Another issue is that you buttonX() functions change the global variable score without gloal keyword:
def button1():
global score
score = score - 1
You just need to remove the while and replace it with a call to after. I also cleaned up your script a little, and solved a future problem you were going to have. Using threading like the other answer states is overkill. You just need to stop blocking the mainloop with the while.
import tkinter as tk
window = tk.Tk()
window.geometry("300x200")
_PLAYTIME = 10
t, score = _PLAYTIME, 0
def tally(i):
global score
score += i
start = tk.Button(window, text="Start")
start.pack(padx= 2, pady = 1)
tk.Button(window, text="Player 1", command=lambda: tally(1)).pack(padx=2, pady=1)
tk.Button(window, text="Player 2", command=lambda: tally(-1)).pack(padx=2, pady=1)
def game():
global t, score
if t > 0:
timer = '{:02d}:{:02d}'.format(*divmod(t, 60))
start.config(text=f'Time: {timer} | Score: {score}')
t -= 1
start.after(1000, game)
else:
start.config(text=f'Score: {score} | Start')
t, score = _PLAYTIME, 0
start.configure(command=game)
window.mainloop()
Here's the exact same game, but made giant and colorful as I assume 4 year olds like things... ;). I also added a 3-2-1-Go! countdown after start is pressed so, the person pressing start doesn't lose an advantage. The red and green rects are your click area. Red subtracts and green adds.
I'm not sure if you are prepared for this but, plugging 2 mice into the same computer is not going to give you 2 pointers. Maybe that's part of your game ~ fighting a 4 year old for mouse control :D. If it isn't, you are going to need TeamPlayer or something similar. Or you could simply bind keyboard keys instead of the mouse.
import tkinter as tk
root = tk.Tk()
root.geometry("800x640")
root.title('CLICKFIGHT')
#seconds to play and player handicaps
_PLAYTIME = 10
_HANDICAP1 = 0
_HANDICAP2 = 0
#time, score, countdown
t, s, cd = _PLAYTIME, 0, 3
#gameboard
board = tk.Canvas(root, highlightthickness=0, width=800, height=640)
board.pack()
#score adjuster
def tally(i):
global s
s += i
#gameboard elements
player1 = board.create_rectangle(0, 0, 400, 600, fill="#ff0000")
player2 = board.create_rectangle(400, 0, 800, 600, fill="#00ff00")
timer = board.create_text(200, 50, font='Helvetica 40 bold', fill='#ffffff')
score = board.create_text(600, 50, font='Helvetica 40 bold', fill='#ffffff')
button = board.create_rectangle(0, 600, 800, 640, fill="#0000ff", tag="button")
start = board.create_text(400, 620, font='Helvetica 20 bold', fill='#ffffff', text="START", tag="button")
cdown = board.create_text(400, 300, font='Helvetica 80 bold', fill='#ffffff')
#game countdown
def countdown():
global cd, p
#so you can't click start again
board.tag_unbind("button", '<1>')
if cd > 0:
board.itemconfig(cdown, text=cd)
cd-=1
root.after(800, countdown)
else:
board.itemconfig(cdown, text='GO!')
root.after(200, game)
cd = 3
#actual game
def game():
global t, s
#game stats
board.itemconfig(timer, text='Time:\t{:02d}:{:02d}'.format(*divmod(t, 60)))
board.itemconfig(score, text=f'Score:\t{s}')
board.itemconfig(start, text='PLAYING...')
if t > 0:
#game looping
t -= 1
root.after(1000, game)
board.itemconfig(cdown, text='')
else:
#reset everything
t, s = _PLAYTIME, 0
board.itemconfig(start, text='START')
board.itemconfig(cdown, text='GAME OVER')
board.tag_bind("button", '<1>', lambda e: countdown())
#mouse events
board.tag_bind(player1 , '<1>', lambda e: tally(-(1+_HANDICAP1)))
board.tag_bind(player2 , '<1>', lambda e: tally(1+_HANDICAP2))
board.tag_bind("button", '<1>', lambda e: countdown())
root.mainloop()

How can we use an Entry to set Time on Timer? (Python, tkinter)

I started coding just a few days ago, so I hope you can help me :)
I'm trying to connect an entry with my timer. So user can choose which time they want to set. They can set the value in minutes. I already got it to get the value of the entry in my timer, but the timer won't start. I'm using tkinter to code this.
So if the user enters e.g. "3" my timer will display "03:00" but time won't start running. The console is printing no errors either. Here is my code:
from tkinter import *
from PIL import ImageTk, Image
import math
window = Tk()
window.title("u'Clock")
window.config(padx=50, pady=50, bg="#1a1c20", highlightthickness=0)
timer = None
def start_timer():
count_down(0)
def get_time():
time = input_time_do.get()
int_time = int(time)
return int_time
def count_down(count):
count = get_time()
count_min = count
count_sec = count*60 % 60
if count_min < 10:
count_min = f"0{count_min}"
if count_sec < 10:
count_sec = f"0{count_sec}"
canvas.itemconfig(timer_text, text=f"{count_min}:{count_sec}")
if count > 0:
global timer
window.after(1000, count_down, count - 1)
input_time_do = Entry(width="20", background="DarkSeaGreen")
input_time_do.insert(END, string="Set Workout Time")
input_time_do.grid(column=1, row=2, padx=10, pady=10)
start_button = Button(text="START", command=start_timer)
start_button.grid(column=1, row=6, padx=10, pady=10)
canvas = Canvas(width=400, height=266, bg="#fbf7f0", highlightthickness=0)
gym_img = ImageTk.PhotoImage(Image.open("gym1.jpg")) # PIL solution
canvas.create_image(200, 133, image=gym_img)
timer_text = canvas.create_text(200, 135, text="00:00", fill="#fbf7f0", font=
("Roboto", 30))
canvas.grid(column=1, row=1)
window.mainloop()

Issues in time delay for RSS feed on full screen clock python

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.

Categories