Call a fonction from message box Tkinter - python

I want to call the fonction (submit) after clicking on the message box. With this code I have to reclick on button everytime after the messagebox but would appreciate if the timer launch automatically after clicking on the message box.
If anyone have a clue I will appreciate.
The following code :
import time
from tkinter import *
root = Tk()
root.resizable(width=False, height=False)
root.geometry("300x250")
root['background']='#39E5F9'
root.title("Time To Drink Water")
minute = StringVar()
second = StringVar()
minute.set("45")
second.set("00")
minuteEntry = Entry(root, width=3, font=("Arial", 35, ""),
textvariable=minute,justify='center')
minuteEntry.place(x=50, y=60)
secondEntry = Entry(root, width=3, font=("Arial", 35, ""),
textvariable=second,justify='center')
secondEntry.place(x=170, y=60)
def submit():
# stored in here : 2700 = 45 mins
temp = 2700
while temp > -1:
# divmod(firstvalue = temp//60, secondvalue = temp%60)
mins, secs = divmod(temp, 60)
if mins > 60:
hours, mins = divmod(mins, 60)
minute.set("{0:2d}".format(mins))
second.set("{0:2d}".format(secs))
root.update()
time.sleep(1)
if (temp == 0):
messagebox.showinfo("Time Countdown", "Time To Drink !")
temp -= 1
def go():
btn = Button(root, text='Goodbye dehydration!', bd='6',
command=submit)
btn.place(x=90, y=160)
go()
root.mainloop()

messagebox is waiting for your click so you can run submit() after messagebox and it will run it after clicking in messagebox
But you shouldn't use while and sleep because it may freeze GUI (in any framework, and in any language). You can use root.after(1000, function) to run function again after 1000ms (1s) and it will work as sleep and while together.
import time
import tkinter as tk # PEP8: `import *` is not preferred
from tkinter import messagebox
# --- functions --- # PEP8: all functions before main code
def submit():
update_counter(2700)
def update_counter(temp):
if temp > -1: # `if` instead of `while` because `after` will work as loop
# divmod(firstvalue = temp//60, secondvalue = temp%60)
mins, secs = divmod(temp, 60)
if mins > 60:
hours, mins = divmod(mins, 60)
minute.set("{:02d}".format(mins)) # use `:02` to get `09` instead of ` 9` (with space)
second.set("{:02d}".format(secs))
temp -= 1
root.after(1000, update_counter, temp) # run again after 1000ms
else:
messagebox.showinfo("Time Countdown", "Time To Drink !")
root.after(0, update_counter, 2700) # run again after 0ms
#update_counter(2700) # run again
# --- main --- # PEP8: `lower_case_names` for variables
running = False
temp = 2700
root = tk.Tk()
minute = tk.StringVar(root)
second = tk.StringVar(root)
minute.set("45")
second.set("00")
minute_entry = tk.Entry(root, width=3, textvariable=minute, font=("Arial", 35, ""), justify='center')
minute_entry.grid(row=0, column=0)
second_entry = tk.Entry(root, width=3, textvariable=second, font=("Arial", 35, ""), justify='center')
second_entry.grid(row=0, column=1)
btn = tk.Button(root, text='Goodbye dehydration!', command=submit)
btn.grid(row=1, column=0, columnspan=2)
root.mainloop()
PEP 8 -- Style Guide for Python Code
There is other problem. You can click button two times and it will run two update_counter() at the same time. It may need to disable button, or you would have to use boolean variable - ie. running = False - to control if it has to run update_counter() or not.

Related

How to create mutliple child windows from tkinter root window?

I am new to python and learning tkinter apps. I am trying to build an app that can spawn multiple instances of countdown timer and run them separately. I have been able to create a template code and can run one child window successfully but when I open another child window first one pauses and only the last one runs.
MWE
How to make all the child window countdown timers run separately?
Problem: If I click Scripts menu, then the countdown pauses itself.
%%writefile a.py
import time
import tkinter as tk
from tkinter import ttk,messagebox
def countdown(win):
child = tk.Toplevel(win)
child.geometry('400x300')
child.resizable(0, 0)
def _show_current_clock_time(label):
str_clock_time = time.strftime('%H:%M:%S %p')
label.config(text=str_clock_time)
label.after(1000, lambda: _show_current_clock_time(label))
def _countdown(child,v_hrs,v_mins,v_secs,int_secs):
if int_secs is not None:
total_seconds = int_secs
else:
total_seconds = int(v_hrs.get()) * 3600 + int(v_mins.get()) * 60 + int(v_secs.get())
while total_seconds > -1:
minute, second = (total_seconds // 60, total_seconds % 60)
hour = 0
if minute > 60:
hour, minute = (minute // 60, minute % 60)
v_secs.set(second);v_mins.set(minute);v_hrs.set(hour)
child.update();time.sleep(1)
if (total_seconds == 0):
messagebox.showinfo('Times Up!')
v_secs.set('00');v_mins.set('00');v_hrs.set('00')
total_seconds -= 1
tk.Label(child,text='Countdown Clock and Timer').pack()
tk.Label(child, font='arial 15 bold', text='current time :').place(x=40, y=70)
# label: current time body
l_curr_time = tk.Label(child)
l_curr_time.place(x=190, y=70)
_show_current_clock_time(l_curr_time)
# variables: secs mins hrs
v_secs = tk.StringVar()
e_secs = tk.Entry(child, textvariable=v_secs, width=2, font='arial 12')
e_secs.place(x=250, y=155)
v_secs.set('00')
v_mins = tk.StringVar()
e_mins = tk.Entry(child, textvariable=v_mins, width=2, font='arial 12')
e_mins.place(x=225, y=155)
v_mins.set('00')
v_hrs = tk.StringVar()
e_hrs = tk.Entry(child, textvariable=v_hrs, width=2, font='arial 12')
e_hrs.place(x=200, y=155)
v_hrs.set('00')
# label: set the time
tk.Label(child, font='arial 15 bold', text='set the time',bg='papaya whip').place(x=40, y=150)
# button: start
x,w = 0,40
tk.Button(child,text='Run',bd='1',
command= lambda x=[child,v_hrs,v_mins,v_secs,None]: _countdown(x[0],x[1],x[2],x[3],x[4])).place(x=280, y=150)
for i,minn in enumerate([1,2,3,4]):
tk.Button(child,text=str(minn)+'m',
command= lambda x=[child,v_hrs,v_mins,v_secs,minn*60]: _countdown(
x[0],x[1],x[2],x[3],x[4]),).place(x=x+w*i, y=200)
win = tk.Tk()
menubar = tk.Menu(win)
menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label="Scripts", menu=menu)
menu.add_command(label='Countdown',command=lambda : countdown(win))
menu.add_command(label='Countdown 2',command=lambda : countdown(win))
menu.add_command(label='Countdown 3',command=lambda : countdown(win))
win.config(menu=menubar)
win.mainloop()

My code from tkinter counter crashes on execution. I am not sure why

I copied this code to try to make a countdown app in tkiner. Whenever I run the code and click the generated button, it just just keeps loading, and I have to force quit. I am wondering if there is something wrong with this code? Everything seems to generate fine, the only problems seems to be the button click and execution.
import time
from tkinter import *
from tkinter import messagebox
root = Tk()
root.geometry("300x250")
root.title("Time Counter")
hour=StringVar()
minute=StringVar()
second=StringVar()
hour.set("00")
minute.set("00")
second.set("00")
hourEntry= Entry(root, width=3, font=("Arial",18,""),
textvariable=hour)
hourEntry.place(x=80,y=20)
minuteEntry= Entry(root, width=3, font=("Arial",18,""),
textvariable=minute)
minuteEntry.place(x=130,y=20)
secondEntry= Entry(root, width=3, font=("Arial",18,""),
textvariable=second)
secondEntry.place(x=180,y=20)
def submit():
try:
temp = int(hour.get())*3600 + int(minute.get())*60 + int(second.get())
except:
print("Please input the right value")
while temp >-1:
mins,secs = divmod(temp,60)
hours=0
if mins >60:
hours, mins = divmod(mins, 60)
hour.set("{0:2d}".format(hours))
minute.set("{0:2d}".format(mins))
second.set("{0:2d}".format(secs))
root.update()
time.sleep(1)
if (temp == 0):
messagebox.showinfo("Time Countdown", "Time's up ")
temp -= 1
btn = Button(root, text='Set Time Countdown', bd='5',
command= submit)
btn.place(x = 70,y = 120)
root.mainloop()

Combine two windows with tkinter

I have just started playing with tkinter today and I have two bit of code I have been playing with as examples however I am struggling to combine these can anyone advise. I would like to clock to display in the main window.
import tkinter
from tkinter import *
import sys
import time
root = Tk()
root.title('Logging')
Label(text='Time logging').pack(side=TOP,padx=100,pady=100)
entry = Entry(root, width=25)
entry.pack(side=TOP,padx=25,pady=25)
def onok():
x, y = entry.get().split('x')
for row in range(int(y)):
for col in range(int(x)):
print((col, row))
Button(root, text='Log Time', command=onok).pack(side=LEFT)
Button(root, text='CLOSE').pack(side= RIGHT)
def tick():
global time1
# get the current local time from the PC
time2 = time.strftime('%H:%M:%S')
# if time string has changed, update it
if time2 != time1:
time1 = time2
clock.config(text=time2)
# calls itself every 200 milliseconds
# to update the time display as needed
# could use >200 ms, but display gets jerky
clock.after(200, tick)
root = Tk()
time1 = ''
status = Label(root, text="v1.0", bd=1, relief=SUNKEN, anchor=W)
status.grid(row=10, column=10)
clock = Label(root, font=('times', 20, 'bold'), bg='green')
clock.grid(row=0, column=1)
tick()
root.mainloop()
You can use Frame to group clock widgets and use grid inside this frame. And frame you can put in main window. (And you don't need second Tk())
I put it at the top but you can choose other place.
import tkinter as tk
import time
# --- functions ---
def on_ok():
x, y = entry.get().split('x')
for row in range(int(y)):
for col in range(int(x)):
print((col, row))
def tick():
global time1
# get the current local time from the PC
time2 = time.strftime('%H:%M:%S')
# if time string has changed, update it
if time2 != time1:
time1 = time2
clock.config(text=time2)
# calls itself every 200 milliseconds
# to update the time display as needed
# could use >200 ms, but display gets jerky
clock.after(200, tick)
# --- main window ---
time1 = ''
root = tk.Tk()
root.title('Logging')
# add frame in main window (root)
other = tk.Frame(root)
other.pack()
# put widgets in frame (other)
status = tk.Label(other, text="v1.0", bd=1, relief=tk.SUNKEN, anchor=tk.W)
status.grid(row=10, column=10)
clock = tk.Label(other, font=('times', 20, 'bold'), bg='green')
clock.grid(row=0, column=1)
# put other widget directly in main widnow (root)
tk.Label(root, text='Time logging').pack(side=tk.TOP, padx=100, pady=100)
entry = tk.Entry(root, width=25)
entry.pack(side=tk.TOP, padx=25, pady=25)
tk.Button(root, text='Log Time', command=on_ok).pack(side=tk.LEFT)
tk.Button(root, text='CLOSE', command=root.destroy).pack(side= tk.RIGHT)
tick()
# --- start ---
root.mainloop()
You have two different root windows. Use one root = Tk() line at the top and you should have them on the same page.

How to make a Tkinter window not resizable?

I need a Python script that uses the Tkinter module to create a static (not resizable) window.
I have a pretty simple Tkinter script but I don't want it to be resizable. How do I prevent a Tkinter window from being resizable? I honestly don't know what to do.
This is my script:
from tkinter import *
import ctypes, os
def callback():
active.set(False)
quitButton.destroy()
JustGo = Button(root, text=" Keep Going!", command= lambda: KeepGoing())
JustGo.pack()
JustGo.place(x=150, y=110)
#root.destroy() # Uncomment this to close the window
def sleep():
if not active.get(): return
root.after(1000, sleep)
timeLeft.set(timeLeft.get()-1)
timeOutLabel['text'] = "Time Left: " + str(timeLeft.get()) #Update the label
if timeLeft.get() == 0: #sleep if timeLeft = 0
os.system("Powercfg -H OFF")
os.system("rundll32.exe powrprof.dll,SetSuspendState 0,1,0")
def KeepGoing():
active.set(True)
sleep()
quitButton1 = Button(root, text="do not sleep!", command=callback)
quitButton1.pack()
quitButton1.place(x=150, y=110)
root = Tk()
root.geometry("400x268")
root.title("Alert")
root.configure(background='light blue')
timeLeft = IntVar()
timeLeft.set(10) # Time in seconds until shutdown
active = BooleanVar()
active.set(True) # Something to show us that countdown is still going.
label = Label(root, text="ALERT this device will go to sleep soon!", fg="red")
label.config(font=("Courier", 12))
label.configure(background='light blue')
label.pack()
timeOutLabel = Label(root, text = 'Time left: ' + str(timeLeft.get()), background='light blue') # Label to show how much time we have left.
timeOutLabel.pack()
quitButton = Button(root, text="do not sleep!", command=callback)
quitButton.pack()
quitButton.place(x=150, y=110)
root.after(0, sleep)
root.mainloop()
The resizable method on the root window takes two boolean parameters to describe whether the window is resizable in the X and Y direction. To make it completely fixed in size, set both parameters to False:
root.resizable(False, False)

How do I create an automatically updating GUI using Tkinter?

from Tkinter import *
import time
#Tkinter stuff
class App(object):
def __init__(self):
self.root = Tk()
self.labeltitle = Label(root, text="", fg="black", font="Helvetica 40 underline bold")
self.labeltitle.pack()
self.labelstep = Label(root, text="", fg="black", font="Helvetica 30 bold")
self.labelstep.pack()
self.labeldesc = Label(root, text="", fg="black", font="Helvetica 30 bold")
self.labeldesc.pack()
self.labeltime = Label(root, text="", fg="black", font="Helvetica 70")
self.labeltime.pack()
self.labelweight = Label(root, text="", fg="black", font="Helvetica 25")
self.labelweight.pack()
self.labelspeed = Label(root, text="", fg="black", font="Helvetica 20")
self.labelspeed.pack()
self.labeltemp = Label(root, text="", fg="black", font="Helvetica 20")
self.labeltemp.pack()
self.button = Button(root, text='Close recipe', width=25, command=root.destroy)
self.button.pack()
def Update(self, label, change):
label.config(text=str(change))
def main():
app = App()
app.mainloop()
if __name__ == "__main__":
main()
I'm trying to create a recipe display which will show the step, instructions, weight and other variables on a screen in a Tkinter GUI.
However, I do not know how to update the GUI to change with each new step of the recipe, as the content has to be dynamically updated based on user input (taken from a server). How can I achieve updating of the GUI's other elements based on the change in steps?
You can use after() to run function after (for example) 1000 miliseconds (1 second) to do something and update text on labels. This function can run itself after 1000 miliseconds again (and again).
It is example with current time
from Tkinter import *
import datetime
root = Tk()
lab = Label(root)
lab.pack()
def clock():
time = datetime.datetime.now().strftime("Time: %H:%M:%S")
lab.config(text=time)
#lab['text'] = time
root.after(1000, clock) # run itself again after 1000 ms
# run first time
clock()
root.mainloop()
BTW: you could use StringVar as sundar nataraj Сундар suggested
EDIT: (2022.01.01)
Updated to Python 3 with other changes suggested by PEP 8 -- Style Guide for Python Code
import tkinter as tk # PEP8: `import *` is not preferred
import datetime
# --- functions ---
# PEP8: all functions before main code
# PEP8: `lower_case_name` for funcitons
# PEP8: verb as function's name
def update_clock():
# get current time as text
current_time = datetime.datetime.now().strftime("Time: %H:%M:%S")
# udpate text in Label
lab.config(text=current_time)
#lab['text'] = current_time
# run itself again after 1000 ms
root.after(1000, update_clock)
# --- main ---
root = tk.Tk()
lab = tk.Label(root)
lab.pack()
# run first time at once
update_clock()
# run furst time after 1000ms (1s)
#root.after(1000, update_clock)
root.mainloop()
if you want to change label dynamically
self.dynamiclabel=StringVar()
self.labeltitle = Label(root, text=self.dynamiclabel, fg="black", font="Helvetica 40 underline bold")
self.dyanamiclabel.set("this label updates upon change")
self.labeltitle.pack()
when ever you get new value then just use .set()
self.dyanamiclabel.set("Hurrray! i got changed")
this apply to all the labels.To know more read this docs
If you are using labels, then you can use this:
label = tk.Label(self.frame, bg="green", text="something")
label.place(rely=0, relx=0.05, relwidth=0.9, relheight=0.15)
refresh = tk.Button(frame, bg="white", text="Refreshbutton",command=change_text)
refresh.pack(rely=0, relx=0.05, relwidth=0.9, relheight=0.15)
def change_text()
label["text"] = "something else"
Works fine for me, but it is dependent on the need of a button press.
I added a process bar in my window, and change its value according to randint for every 1 second using the update function:
from random import randint
def update():
mpb["value"] = randint(0, 100) # take process bar for example
window.after(1000, update)
update()
window.mainloop()
I wrote an example with Python 3.7
from tkinter import *
def firstFrame(window):
global first_frame
first_frame = Frame(window)
first_frame.place(in_=window, anchor="c", relx=.5, rely=.5)
Label(first_frame, text="ATTENTION !").grid(row=1,column=1,columnspan=3)
def secondFrame(window):
global second_frame
second_frame= Frame(window, highlightbackground=color_green, highlightcolor=color_green, highlightthickness=3)
second_frame.place(in_=window, anchor="c", relx=.5, rely=.5)
Label(second_frame, text="This is second frame.").grid(row=1, column=1, columnspan=3, padx=25, pady=(15, 0))
window = Tk()
window.title('Some Title')
window.attributes("-fullscreen", False)
window.resizable(width=True, height=True)
window.geometry('300x200')
firstFrame(window)
secondFrame(window)
first_frame.tkraise()
window.after(5000, lambda: first_frame.destroy()) # you can try different things here
window.mainloop()
Use root.config() and add a way to run

Categories

Resources