Time Changing Without Clicking Button - python

The following code works fine as long as the time in the spinbox does not change. What I want is to do the set the time for a break. The first time it works perfectly but after that if I change the value in the spinbox, the system will check for new value instead of the value which was in the spinbox when the button is clicked.
from tkinter import *
from tkinter import ttk
from datetime import datetime
root = Tk()
root.title("Fusion Calculator")
first_break_time_label = Label(root, text='1st Break:')
first_break_time_label.grid(row=0, column=0)
first_break_time_hour = Spinbox(root, from_=0, to=23, format='%02.0f')
first_break_time_hour.grid(row=0, column=1)
first_break_time_minute = Spinbox(root, from_=0, to=59, format='%02.0f')
first_break_time_minute.grid(row=0, column=2)
first_break_time_second = Spinbox(root, from_=0, to=59, format='%02.0f')
first_break_time_second.grid(row=0, column=3)
loop_active = False # global variable set to false
def check_breaks(): # new loop function that runs set_breaks and reschedules
set_breaks() # for 1 second later.
root.after(1000, check_breaks)
def set_breaks():
check_break = datetime.now().strftime("%H:%M:%S")
first_break_time_value = f'{first_break_time_hour.get()}:{first_break_time_minute.get()}:{first_break_time_second.get()}'
if check_break == first_break_time_value:
popup_first_break = Toplevel(root)
popup_first_break.title('Official Break')
popup_first_break_title_bar = Label(popup_first_break, text='OFFICIAL BREAK', fg='Red')
popup_first_break_title_bar.pack()
else:
pass
global loop_active
if not loop_active: # This will only run when loop_active is false
loop_active = True # Set loop_active to True so it doesn't run again
check_breaks()
set_breaks_button = ttk.Button(root, text='Set', command=set_breaks)
set_breaks_button.grid(row=1, column=3)
root.mainloop()
I tried to bind the button with a mouse click so that it will create an array and get the values into the array. But I am having hard time working with events.

The quick and easy way to do it, would be to create a dictionary that holds each of the breaks values initially set to None, then to populate the dictionary the first time the button is pressed and start the loop at the same time, then have the loop check the dictionary on each iteration for the break times, and set the button command to a function that updates the dictionary when pressed.
For example:
from tkinter import *
from tkinter import ttk
from datetime import datetime
root = Tk()
root.title("Fusion Calculator")
first_break_time_label = Label(root, text='1st Break:')
first_break_time_label.grid(row=0, column=0)
first_break_time_hour = Spinbox(root, from_=0, to=23, format='%02.0f')
first_break_time_hour.grid(row=0, column=1)
first_break_time_minute = Spinbox(root, from_=0, to=59, format='%02.0f')
first_break_time_minute.grid(row=0, column=2)
first_break_time_second = Spinbox(root, from_=0, to=59, format='%02.0f')
first_break_time_second.grid(row=0, column=3)
loop_active = False # global variable set to false
breaks = {
1: None
}
def check_breaks(): # new loop function that runs set_breaks and reschedules
set_breaks() # for 1 second later.
root.after(1000, check_breaks)
def update_break():
first_break_time_value = f'{first_break_time_hour.get()}:{first_break_time_minute.get()}:{first_break_time_second.get()}'
breaks[1] = first_break_time_value
set_breaks()
def set_breaks():
check_break = datetime.now().strftime("%H:%M:%S")
if check_break == breaks[1]:
popup_first_break = Toplevel(root)
popup_first_break.title('Official Break')
popup_first_break_title_bar = Label(popup_first_break, text='OFFICIAL BREAK', fg='Red')
popup_first_break_title_bar.pack()
global loop_active
if not loop_active: # This will only run when loop_active is false
loop_active = True # Set loop_active to True so it doesn't run again
check_breaks()
set_breaks_button = ttk.Button(root, text='Set', command=update_break)
set_breaks_button.grid(row=1, column=3)
root.mainloop()
What might be a better option though would be to start the timed loop at the start of the program that way you can get rid of the loop active variable and extra check function.
Like this:
from tkinter import *
from tkinter import ttk
from datetime import datetime
root = Tk()
root.title("Fusion Calculator")
first_break_time_label = Label(root, text='1st Break:')
first_break_time_label.grid(row=0, column=0)
first_break_time_hour = Spinbox(root, from_=0, to=23, format='%02.0f')
first_break_time_hour.grid(row=0, column=1)
first_break_time_minute = Spinbox(root, from_=0, to=59, format='%02.0f')
first_break_time_minute.grid(row=0, column=2)
first_break_time_second = Spinbox(root, from_=0, to=59, format='%02.0f')
first_break_time_second.grid(row=0, column=3)
breaks = {
1: None
}
def update_break():
first_break_time_value = f'{first_break_time_hour.get()}:{first_break_time_minute.get()}:{first_break_time_second.get()}'
breaks[1] = first_break_time_value
def check_breaks():
check_break = datetime.now().strftime("%H:%M:%S")
if check_break == breaks[1]:
popup_first_break = Toplevel(root)
popup_first_break.title('Official Break')
popup_first_break_title_bar = Label(popup_first_break, text='OFFICIAL BREAK', fg='Red')
popup_first_break_title_bar.pack()
root.after(1000, check_breaks)
check_breaks()
set_breaks_button = ttk.Button(root, text='Set', command=update_break)
set_breaks_button.grid(row=1, column=3)
root.mainloop()

Related

How to change the theme of my tkinter application in Python?

I'm trying to change my Tkinter theme but when I change s.theme_use('classic') to s.theme_use('calm') or s.theme_use('winnative') nothing changes.
Here is my code:
from tkinter import *
import tkinter.ttk as ttk
window = Tk()
window.title("Running Python Script") # Create window
window.geometry('550x300') # geo of the window
s=ttk.Style()
list_themes = s.theme_names()
current_theme = s.theme_use()
s.theme_use('classic')
print(list_themes)
def run():
if dd_owner.get() == "Spain":
print("spain")
# These are the option menus
dd_owner = StringVar(window)
dd_owner.set(owner[0]) # the first value
w = OptionMenu(window, dd_owner, *owner)
w.grid(row=0, column=1)
#The run button
run_button = Button(window, text="Run application {}".format(dd_owner.get()), bg="blue", fg="white",command=run)
run_button.grid(column=0, row=2)
# These are the titles
l1 = Label(window, text='Select Owner', width=15)
l1.grid(row=0, column=0)
mainloop()
Below is an modified example using ttk widgets based on your code:
from tkinter import *
import tkinter.ttk as ttk
import random
window = Tk()
window.title("Running Python Script") # Create window
window.geometry('550x300') # geo of the window
s=ttk.Style()
s.configure("TButton", foreground="red", background="blue")
list_themes = s.theme_names()
current_theme = s.theme_use()
#s.theme_use('classic')
print(list_themes)
def run():
if dd_owner.get() == "Spain":
print("spain")
# choose a theme randomly
theme = random.choice(list_themes)
print("theme:", theme)
s.theme_use(theme)
# These are the option menus
owner = ("Spain", "France", "Germany")
dd_owner = StringVar(window)
dd_owner.set(owner[0]) # the first value
#w = OptionMenu(window, dd_owner, *owner)
# use ttk.Combobox instead of OptionMenu
w = ttk.Combobox(window, textvariable=dd_owner, values=owner)
w.grid(row=0, column=1)
#The run button
#run_button = Button(window, text="Run application {}".format(dd_owner.get()), bg="blue", fg="white",command=run)
# use ttk.Button
run_button = ttk.Button(window, text="Run application {}".format(dd_owner.get()), command=run)
run_button.grid(column=0, row=2)
# These are the titles
l1 = ttk.Label(window, text='Select Owner', width=15)
l1.grid(row=0, column=0)
mainloop()
When you click the button, it will change the theme randomly.

How to overwrite a Timer in Python

I have 2 buttons(rotate and reverse). When either button is ON the other is deactivated as both cannot be on at the same time. When On button is turned OFF, it gives the disabled button 10 seconds before back to Normal.
My question is How can I stop the 10sec timer if I was to hit ON(same button turned off) before the 10 second timer. Example, If I turn ON rotate then OFF(this starts 10 second timer for Reverse) but if decide to turn rotate ON again my timer to reverse button is still counting. How can I stop the timer, so that if I turn OFF again it can start new 10sec?
\\
from tkinter import *
from tkinter import font
from threading import Timer
from time import sleep
reverse_motor = True
rotate_motor = True
def hp30():
global rotate_motor
# Turn ON 30hp Motor
if rotate_motor:
rotate_motor = False
motor30hp.config(activebackground=motor30hp.cget('background'))
reverseButton["state"] = DISABLED
motor30hp["text"] = "ON"
motor30hp["bg"] = "green"
print("30hp Motor ON")
motor30hp.config(activebackground=motor30hp.cget('background'))
else:
# Turn OFF 30hp Motor
rotate_motor = True
motor30hp["text"] = "OFF"
motor30hp["bg"] = "red"
print("30hp Motor OFF")
motor30hp.config(activebackground=motor30hp.cget('background'))
tim01 = Timer(10, normal_reverse)
tim01.start()
print("Reverse 10 sec Timer On")
def reverse():
global reverse_motor
if reverse_motor:
reverse_motor = False
motor30hp["state"] = DISABLED
print("Rotate Disabled")
reverseButton.config(activebackground=reverseButton.cget('background'))
print("Reverse Motor ON")
reverseButton["text"] = "ON"
reverseButton["bg"] = "green"
else:
reverse_motor = True
reverseButton["text"] = "OFF"
reverseButton["bg"] = "red"
reverseButton.config(activebackground=reverseButton.cget('background'))
print("Reverse Motor OFF")
timer = Timer(10, normal_hp30)
timer.start()
print("Rotate 10 sec Timer On")
def normal_hp30():
motor30hp.config(state='normal')
print("Rotate Enabled")
def normal_reverse():
reverseButton.config(state='normal')
print("Reverse Enabled")
root = Tk()
root.title("SOTS Remote")
root.geometry('400x150+0+0')
root.configure(background="black")
myFont = font.Font(family='Times', size=30, weight='bold')
#-------------------------------lABELS--------------------------------------------------------
root.label2 = Label(root, text="Rotate", font=myFont, fg="white", bg="black")
root.label2.grid(row=0, column=1, sticky="W", padx=25, pady=2)
root.label3 = Label(root, text="Reverse", font=myFont, fg="white", bg="black", padx=30)
root.label3.grid(row=0, column=0, sticky="NW", pady=2)
#----------------------------------------buttons--------------------------------------------------
reverseButton = Button(root, text="OFF", font=myFont, height=1, width=7, bg='dodgerblue',
command=reverse, relief=RIDGE,bd=5)
reverseButton.grid(row=1, column=0, sticky="NW")
reverseButton.config(activebackground=reverseButton.cget('background'))
motor30hp = Button(root, text="OFF", bg='red', relief=RIDGE, bd=5, font=myFont,
command=hp30, height=1, width=7)
motor30hp.grid(row=1, column=1, sticky="W")
motor30hp.config(activebackground=motor30hp.cget('background'))
root.mainloop()
\\

How to write function to add the number of the button clicked to the PIN number entry via its associated variable?

I am trying to build virtual numpad(with 1,2 and 3) using python and tkinter .
If I press 1 (button1) then account_number_entry should change to 1 and if i press 2 than account_number_entry should change accordingly.
I tried this code but.
import tkinter as tk
win = tk.Tk()
def handle_pin_button(event):
'''Function to add the number of the button clicked to the PIN number entry via its associated variable.'''
# Limit to 4 chars in length
# Set the new pin number on the pin_number_var
def create_login_screen():
accLabel = tk.Label(win, text="Acount Number / Pin")
accLabel.grid(row=1, column=0)
account_number_var = tk.StringVar()
account_number_entry = tk.Entry(win, textvariable=account_number_var)
account_number_entry.grid(row=1, column=1)
account_number_entry.focus_set()
pin_number_var = tk.StringVar()
account_pin_entry = tk.Entry(win, show='*', text='PIN Number', textvariable=pin_number_var)
account_pin_entry.grid(row=1, column=2)
# Buttons 1, 2 and 3 here. Buttons are bound to 'handle_pin_button' function via '<Button-1>' event.
button1 = tk.Button(text="1")
button1.bind('<Button-1>', handle_pin_button)
button1.grid(row=2, column=0, sticky="NESW")
button2 = tk.Button(text="2")
button2.bind('<Button-1>', handle_pin_button)
button2.grid(row=2, column=1, sticky="NESW")
button3 = tk.Button(text="3")
button3.bind('<Button-1>', handle_pin_button)
button3.grid(row=2, column=2, sticky="NESW")
create_login_screen()
tk.mainloop()
You need to create the account_number_var outside the function create_login_screen() or it will be garbage collected when the function exits.
The usual way to bind a button to a function is to use the argument command. When you have a single function which handles callback from many buttons the usual way is to use lambda.
Example below:
import tkinter as tk
win = tk.Tk()
account_number_var = tk.StringVar() # Create outside function
pin_number_var = tk.StringVar()
def handle_pin_button(digit):
account_number_var.set(digit)
def create_login_screen():
accLabel = tk.Label(win, text="Acount Number / Pin")
accLabel.grid(row=1, column=0)
account_number_entry = tk.Entry(win, textvariable=account_number_var)
account_number_entry.grid(row=1, column=1)
account_number_entry.focus_set()
account_pin_entry = tk.Entry(win, show='*', text='PIN Number',
textvariable=pin_number_var)
account_pin_entry.grid(row=1, column=2)
# Buttons 1, 2 and 3 here. Buttons are bound to 'handle_pin_button' function via '<Button-1>' event.
button1 = tk.Button(text="1", command=lambda:handle_pin_button("1"))
button1.grid(row=2, column=0, sticky="NESW")
button2 = tk.Button(text="2", command=lambda:handle_pin_button("2"))
button2.grid(row=2, column=1, sticky="NESW")
button3 = tk.Button(text="3", command=lambda:handle_pin_button("3"))
button3.grid(row=2, column=2, sticky="NESW")
create_login_screen()
win.mainloop()
How to do this with bind() instead of button command:
First you need to keep track of the buttons. Since they are created inside a function you must save a reference in the global scope.
Second you must calculate the button value from the list index and set the account_number_var accordingly.
Then bind the buttons to the callback handler.
import tkinter as tk
win = tk.Tk()
account_number_var = tk.StringVar() # Create outside function
pin_number_var = tk.StringVar()
button_list = [] # Global button reference list
def handle_pin_button(event):
button_number = button_list.index(event.widget) + 1
account_number_var.set(str(button_number))
def create_login_screen():
accLabel = tk.Label(win, text="Acount Number / Pin")
accLabel.grid(row=1, column=0)
account_number_entry = tk.Entry(win, textvariable=account_number_var)
account_number_entry.grid(row=1, column=1)
account_number_entry.focus_set()
account_pin_entry = tk.Entry(win, show='*', text='PIN Number',
textvariable=pin_number_var)
account_pin_entry.grid(row=1, column=2)
# Buttons 1, 2 and 3 here. Buttons are bound to 'handle_pin_button' function via '<Button-1>' event.
button1 = tk.Button(text="1")
button1.grid(row=2, column=0, sticky="NESW")
button1.bind('<Button-1>', handle_pin_button)
button_list.append(button1) # Add button to global list
button2 = tk.Button(text="2")
button2.grid(row=2, column=1, sticky="NESW")
button2.bind('<Button-1>', handle_pin_button)
button_list.append(button2) # Add button to global list
button3 = tk.Button(text="3")
button3.grid(row=2, column=2, sticky="NESW")
button3.bind('<Button-1>', handle_pin_button)
button_list.append(button3) # Add button to global list
create_login_screen()
win.mainloop()

Python - Tkinter - Label Not Updating

Any ideas why the leftresult_label label does not update? The function seems to work but the label does not update. I have looked everywhere and can't find an answer. The 'left' value gets set but the label does not change.
from tkinter import *
root = Tk(className="Page Calculator")
read = IntVar()
total = IntVar()
left = IntVar()
read.set(1)
total.set(1)
left.set(1)
read_label = Label(root,text="Pages Read:")
read_label.grid(column=1, row=1)
total_label = Label(root,text="Total Pages:")
total_label.grid(column=1, row=2)
read_entry = Entry(root,textvariable=read)
read_entry.grid(column=2, row=1)
total_entry = Entry(root,textvariable=total)
total_entry.grid(column=2, row=2)
def func1():
left.set(total.get() - read.get())
print(left.get())
calculate_button = Button(root,text="Calculate",command= func1)
calculate_button.grid(column=2, row=3)
percenet_label = Label(root,text="Percent Finished:")
percenet_label.grid(column=1, row=4)
left_label = Label(root,text="Pages Left:")
left_label.grid(column=1, row=5)
percenetresult_label = Label(root,text=left.get())
percenetresult_label.grid(column=2, row=4)
leftresult_label = Label(root,text="")
leftresult_label.grid(column=2, row=5)
root.mainloop()
To make the function do the job, you'd rather have your label:
leftresult_label = Label(root, textvariable=left)
Once it's tkinter class variable, tkinter takes care about when you change the value. Once you click the button,
def func1():
left.set(total.get() - read.get())
percent.set(int(read.get()*100/total.get()))
left and percent values, which are instances of tkinter.IntVar() class have immidiate effect on widgets (labels in this case) where those values are set as textvariable, just as you have it at Entry widgets.
Here is full code:
from tkinter import *
root = Tk(className="Page Calculator")
read = IntVar()
total = IntVar()
left = IntVar()
percent = IntVar()
read.set(1)
total.set(1)
left.set(1)
percent.set(1)
def func1():
left.set(total.get() - read.get())
percent.set(int(read.get()*100/total.get()))
read_label = Label(root,text="Pages Read:")
read_label.grid(column=1, row=1)
read_entry = Entry(root,textvariable=read)
read_entry.grid(column=2, row=1)
total_label = Label(root,text="Total Pages:")
total_label.grid(column=1, row=2)
total_entry = Entry(root,textvariable=total)
total_entry.grid(column=2, row=2)
calculate_button = Button(root,text="Calculate",command= func1)
calculate_button.grid(column=2, row=3)
percenet_label = Label(root,text="Percent Finished:")
percenet_label.grid(column=1, row=4)
left_label = Label(root,text="Pages Left:")
left_label.grid(column=1, row=5)
percenetresult_label = Label(root,textvariable=percent)
percenetresult_label.grid(column=2, row=4)
leftresult_label = Label(root,textvariable=left)
leftresult_label.grid(column=2, row=5)
root.mainloop()
code including progress bar. update_idletasks() used to keep label and progress bar running.
from tkinter import *
from tkinter import ttk
root = Tk()
root.title('Counter Test')
root.iconbitmap('IT.ico')
root.geometry("800x400")
def missing():
while i < 100:
progress1['value'] = i
label1.config(text=progress1['value'])
root.update_idletasks()
i += 1
progress1 = ttk.Progressbar(root, orient=HORIZONTAL, length=250, mode='determinate')
progress1.pack(pady=15)
label1 = Label(root, text="")
label1.pack(pady=15)
button_1 = Button(root, text="Missing", command=missing)
button_1.pack(pady=15)
button_q = Button(root, text="Quit", command=root.destroy)
button_q.pack(pady=15)
root.mainloop()
so to update controls immediately, like updating labels and TreeView elements this code worked for me.
window = tk.Tk()
window.update_idletasks()

Trouble importing a module with radiobuttons - python

Hi I have made a program that runs various other programs. I import the module and it works fine for programs that don't have radiobuttons involved. The programs with radiobuttons work fine when they are ran by themselves. When they are ran through my menu program, the radiobuttons do not give the IntVar values. Anybody have any ideas on how to fix this? The modules are my ow programs but they all use Tkinter. Here is the code for the menu:
from Tkinter import *
def cmd():
if var.get() == 1:
import animal_age_calculator
animal_age_calculator.createDisplay()
if var.get() == 2:
import temperatureCalculator
temperatureCalculator.createDisplay()
if var.get() == 3:
import calculator
calculator.createDisplay()
if var.get() == 4:
import currencyConverter
currencyConverter.createDisplay()
def createDisplay():
global var
root = Tk()
root.title('Calculator')
title = Label(root, text='Please Select which Calculator you would like to use', font=50)
title.grid(row=0, column=0)
calcType = Frame(root)
calcType.grid(row=1, column=0)
var = IntVar()
animal = Radiobutton(calcType, text='Animal Age Calculator', variable=var, value=1)
animal.pack()
tempConverter = Radiobutton(calcType, text='Temperature Calculator', variable=var, value=2)
tempConverter.pack()
calc = Radiobutton(calcType, text='Calculator', variable=var, value=3)
calc.pack()
currency = Radiobutton(calcType, text='Currency Converter', variable=var, value=4)
currency.pack()
select = Button(root, text='Go', command=cmd)
select.grid(row=2, column=0)
root.mainloop()
if __name__ == '__main__':
createDisplay()
Here is the code for one of the radiobutton programs:
from Tkinter import *
def convert(temperature):
global var4
a = var4.get()
print(str(a))
if a == 1:
print 'test2'
display.delete(1.0, END)
finalTemp = int(temperature)*1.8+32
finalTemp = round(finalTemp, 1)
display.insert(INSERT, finalTemp)
if a == 2:
display.delete(1.0,END)
finalTemp = int(temperature)-32/1.8
finalTemp = round(finalTemp, 1)
display.insert(INSERT, finalTemp)
def createDisplay():
global display, var4
root = Tk()
root.title('Temperature Converter')
root.resizable(width=False, height=False)
title = Label(root, text="Welcome to the temperature converter", font=36)
title.grid(row=0, column=1, columnspan=3)
selTemp = LabelFrame(root, text="Please select your temperature")
selTemp.grid(row=1, column=2)
temp = Scale(selTemp, orient=HORIZONTAL, sliderlength=20, from_=0, to=250, length=250, command=convert)
temp.pack()
temperature = temp.get()
displayFrame = LabelFrame(root, text="Your converted temperature is")
displayFrame.grid(row=1, column=3)
display = Text(displayFrame, width=6, height=1)
display.pack()
var4 = IntVar()
tempType = LabelFrame(root, text='Please select your temperature you would like to convert')
tempType.grid(row=1, column=1)
celcius = Radiobutton(tempType, text="Celcius", variable=var4, value=1)
celcius.pack()
fahrenheit = Radiobutton(tempType, text="Fahrenheit", variable=var4, value=2)
fahrenheit.pack()
root.mainloop()
if __name__ == '__main__':
createDisplay()
The crux of the problem is that you're creating two instances of Tk. You can't do that. Tkinter is designed for you to only ever create a single instance of Tk at any one time. Your modules should create instances of Toplevel rather than instances of Tk, and they should not create a new event loop when the module is imported.

Categories

Resources