Tkinter buttons not showing on different screen - python

It works on my monitor (1920x1080) perfectly but when I use my laptop (Also 1920x1080) none of the buttons or the timer shows..... I've tried using 2 different geometry managers to manage the placement of elements. At first I used .place() but that wasn't working/ideal on my laptop so I switched to .grid(). .grid() was working perfectly on my laptop until today. How can I fix this?
Code:
# Required libraries.
# This is for the gui.
import tkinter as tk
# This is for the timer.
from datetime import datetime
# Sets the Timer up.
counter = 66600
running = False
# Defines the timer.
def counter_label(label):
def count():
if running:
global counter
# To manage the initial delay.
if counter==66600:
display="Starting..."
else:
tt = datetime.fromtimestamp(counter)
string = tt.strftime("%H:%M:%S")
display=string
label['text']=display
label.after(1000, count)
counter += 1
# This starts the timer.
count()
# Start function of timer.
def Start(label):
global running
running=True
counter_label(label)
start['state']='disabled'
stop['state']='normal'
reset['state']='normal'
# Stop function of the timer.
def Stop():
global running
start['state']='normal'
stop['state'] ='disabled'
reset['state']='normal'
running = False
# Reset function of the timer.
def Reset(label):
global counter
# Sets the timer to 0.
counter=10800
# If reset is pressed after pressing stop.
if running==False:
reset['state']='disabled'
# This displays CBR when the timer is not in use.
label['text']='CBR'
# If reset is pressed while stopwatch is running.
else:
label['text']='Starting...'
# Declares the gui.
gui = tk.Tk()
# Changes what the gui is called.
gui.title('Car Go Brrrr v1.9')
# Sets Windows size.
gui.geometry("1920x1080")
# Columns
gui.columnconfigure(0, weight=1)
gui.rowconfigure(0, weight=1)
# This gets grid() to work.
for i in range(20):
tk.Frame(gui, width=20, height=20).grid(row=0, column=i)
for j in range(20):
tk.Frame(gui, width=50, height=50).grid(column=0, row=j)
# Pitstop Button
pitButton = tk.Button(gui, text="Call Pitstop")
pitButton.grid(column=18, row=17)
pitButton.config(width=11, height=5)
# Defines the Exit telemetry button.
def clickExitButton():
exit()
# Exit button code.
exButton = tk.Button(gui, text="Exit Telemetry", command=clickExitButton)
exButton.grid(column=18, row=18)
exButton.config(width=11, height=1)
# Timer label text.
label = tk.Label(text="CBR", fg="black", font="Verdana 30 bold")
label.grid(column=18, row=0)
# Start button.
start = tk.Button(text="Start Timer", command=lambda:Start(label))
start.config(width=11, height=1)
start.grid(column=18, row=16)
# Stop button.
stop = tk.Button(text="Stop Timer", state='disabled', command=Stop)
stop.config(width=11, height=1)
stop.grid(column=18, row=15)
# Reset button.
reset = tk.Button(text="Reset Timer", state='disabled', command=lambda:Reset(label))
reset.config(width=11, height=1)
reset.grid(column=18, row=14)
# Never ever ever remove this, this is essential for the gui to work.
gui.mainloop()
Thanks!

Related

How to stop the button's command by clicking another button

Let's say I have button1 which repeatedly changes its position randomly when clicked. I want to have button2 which will stop button1's action, but I haven't found any helpful method for that
from tkinter import *
def move():
# my code
def stop():
#???
master = Tk()
Button1 = Button(master, #some options, command = move).pack()
Button2 = Button(master,#some options, command = stop).pack()
master.mainloop()
So this code I am going to introduce after my research will hopefully satisfy what you need. So first of all, you need a function to move buttons around and secondly, another function to stop the working of the first one's function (i.e., to prevent its movement).
So one way of doing this is to set the state of the other Buttons to DISABLED to grey them out and prevent clicks. So the one I have shown below uses this method.
# Importing tkinter module
from tkinter import *
# Importing random module
import random
# Creating a tkinter window
root = Tk()
# Initialize tkinter window with dimensions 300 x 250
root.geometry('300x250')
# Stop other function
def stop():
btn.config(state=DISABLED)
# Defining func to move on click
def move():
x = random.randint(50,250)
y = random.randint(50,200)
btn.place(x=x, y=y)
# Creating a moving Button
btn = Button(root, text = 'Click me!',command=move)
btn.pack()
# Creating an end movement Button
endbtn = Button(root, text = 'Stop movement!', command=stop).pack()
root.mainloop()
Now coming to the second method, you can use another function that does nothing to modify the movement button's function. An example of this is given below:
# Importing tkinter module
from tkinter import *
# Importing random module
import random
# Creating a tkinter window
root = Tk()
# Initialize tkinter window with dimensions 300 x 250
root.geometry('300x250')
# Stop other function
def stop():
btn.config(command=donothing)
# A function to do nothing
def donothing():
pass
# Defining method on click
def move():
x = random.randint(50,250)
y = random.randint(50,200)
btn.place(x=x, y=y)
# Creating a moving Button
btn = Button(root, text = 'Click me!',command=move)
btn.pack()
# Creating an end movement Button
endbtn = Button(root, text = 'Stop movement!', command=stop).pack()
root.mainloop()
And the last method is to destroy the whole button. You can use the second button to destroy the first button. An example is given for your reference.
# Importing tkinter module
from tkinter import *
# Importing random module
import random
# Creating a tkinter window
root = Tk()
# Initialize tkinter window with dimensions 300 x 250
root.geometry('300x250')
# Destroy the other button
def stop():
btn.destroy()
# Defining method on click
def move():
x = random.randint(50,250)
y = random.randint(50,200)
btn.place(x=x, y=y)
# Creating a moving Button
btn = Button(root, text = 'Click me!',command=move)
btn.pack()
# Creating an end movement Button
endbtn = Button(root, text = 'Stop movement!', command=stop).pack()
root.mainloop()

How to display a value on Tkinter window from a function every second?

So I'm working on a function does something (turns a motor) every second. For counting the second I use time.sleep(1) because I don't know any other way to wait.
def wash_loop(wash_time):
count = 0
dist = 0
global error_flag
error_flag = 0
while (count < wash_time):
if(count%2==0):#going forward
GPIO.output(Motor_IN1,GPIO.HIGH)
GPIO.output(Motor_IN2,GPIO.LOW)
GPIO.output(Motor_EN,GPIO.HIGH)
print(count)
time.sleep(MOTOR_SLEEP)
else:#going backwards
GPIO.output(Motor_IN1,GPIO.LOW)
GPIO.output(Motor_IN2,GPIO.HIGH)
GPIO.output(Motor_EN,GPIO.HIGH)
print(wash_time - count) #want to display this on a Tkinter window instead
time.sleep(MOTOR_SLEEP)
count+=1
dist = distance_check()
if(dist < CRITICAL_DIS):
error_alert()
break
if(count>=wash_time):
GPIO.output(Motor_EN, GPIO.LOW)
break
The Tkinter function that I'm trying to do this in looks like this:
def wash_window():
#create the main window for GUI control applcation
window2 = TK.Tk()
temp = TK.IntVar()
window2.geometry(WINDOW_GEOMETRY)
window2.title("Wash Cycle ")
#create the frame that will hold instructions
frame0 = TK.Frame(window2)
frame0.pack(side=TK.TOP)
TK.Label(frame0, text="You've selected custom wash cycle").grid(row=0,column=0)
TK.Label(frame0, text="Please select the water temperature for the wash.")\
.grid(row=1,column=0)
frame1 = TK.Frame(window2)
frame1.pack(side=TK.TOP)
temp.get()
hot_button = TK.Radiobutton(frame1, text="HOT", variable=temp, value=1 ).grid(row=0, column=0)
cold_button = TK.Radiobutton(frame1, text="COLD", variable=temp, value=2).grid(row=0,column=1)
warm_button = TK.Radiobutton(frame1, text="WARM", variable=temp, value=3).grid(row=0,column=2)
#create the frame that will hold control entry in the window
frame2 = TK.Frame(window2)
frame2.pack(side=TK.TOP)
TK.Label(frame2, text = "Please enter the time below for the wash cycle").grid(row=0,column=0)
user_entry = TK.Entry(frame2)
user_entry.grid(row=1,column=0)
frame3= TK.Frame(window2)
frame3.pack(side=TK.TOP)
start_button = TK.Button(frame3, text="START", command = lambda: wash_cycle(user_entry,temp)).grid(row=0, column=0)
# stop_button = TK.Button(frame3, text="STOP", command = lambda: wash_cycle(user_entry,temp)).grid(row=0, column=1)
quit_button = TK.Button(frame3, text="QUIT", command = window2.destroy).grid(row=0, column=2)
What I'm trying to do is display the countdown (from the entered time to 0) on this Tkinter window as soon as the person presses start in the window. This is different from using the after() function because I want to show a value from a function which is only executing once, only with the exception that it has a loop.
Thank You!
So what you could do is work with threading.
You Need to:
from threading Import Timer
Then you create a timer
your_timer = Timer(the_seconds_you_want_to_wait, the_function_to_call)
You are calling a function with this and in that function you can display anything in your tkinter window.
What I recommend you to do here is create a Label and then change the properties of it.
For example if you want to show a number on a label:
L1 = Label(root, text="your text here")
L1.pack()
Now if you want to edit that later:
L1.configure(text="your new text here")
your_timer.start()
And at the end of your function you Need to Start the timer in order to the create a cycle or just create a Loop for it.

Can't stop timer in python (after and after_cancel)

I am trying to create a timer in a tkinter GUI that initiates on a start button, and stops on a stop button. I am using .after to loop the timer, but I can't correctly integrate .after_cancel. Any advice would be greatly appreciated.
#import python modules
import time
import math
from tkinter import *
#Create a root window to work in
root = Tk()
root.title("CNT Synthesis Controller") #title of file
#Create global variables to be stored
global var_status
global current_time
global start_time
current_time = 0
#Create Labels
myLabel_Status_T = Label(root, text="Total time elapsed (hrs:min:sec):")
myLabel_Timer = Label(root, text="00:00:00")
#Locate labels
myLabel_Status_T.grid(row=0, column=0)
myLabel_Timer.grid(row=1, column=0)
#Start button function
def Click_Start():
#disable Start Button to prevent re-start
myButton_Start.config(state=DISABLED)
#initiate time = 0 and start timer
start_time = time.time()
global Timer_continue
Timer_continue = True
#Timer function
def Timer():
#determine the amount of time passed since start_time measured
current_time = int(time.time()-start_time)
hour = math.floor(current_time/3600)
minute = math.floor((current_time/60)-(hour*60))
second = math.floor(current_time-(hour*3600)-(minute*60))
#shows time as 00:00:00, i.e. adding in the zeroes where needed
if hour<10:
hour=str("0"+str(hour))
else:
hour=str(hour)
if minute<10:
minute=str("0"+str(minute))
else:
minute=str(minute)
if second<10:
second=str("0"+str(second))
else:
second=str(second)
#print the time to the label myLabel_Timer
myLabel_Timer.config(text= hour + ":" + minute + ":" + second)
#after 1000 ms repeat the Timer function
#while (myButton_Stop['state'] != tk.DISABLED):
#Timer_Object=myLabel_Timer.after(1000,Timer)
if Timer_continue == True:
root.after(1000,Timer)
if Timer_continue == False:
root.after_cancel(Timer)
Timer()
#Stop button function
def Click_Stop():
Timer_continue = False
#disable Stop Button to prevent re-use until program is reset
myButton_Stop.config(state=DISABLED)
#Create Buttons
myButton_Start = Button(root,text="Start CNT Synthesis", padx=40, pady=20, fg="white", bg="green", command=Click_Start)
myButton_Stop = Button(root,text="Stop CNT Synthesis", padx=40, pady=20, fg="white", bg="red", command=Click_Stop)
#Locate buttons
myButton_Start.grid(row=2, column=0)
myButton_Stop.grid(row=2, column=1)
root.mainloop()
####---------------------------------------------------------------------Required added text to make the question 'long enough'--------------------------------------------------------------------------------------------##########
You need to save the ID returned by .after() and use it in .after_cancel() to stop the timer inside Click_Stop() function:
#import python modules
import time
from tkinter import *
#Create a root window to work in
root = Tk()
root.title("CNT Synthesis Controller") #title of file
#Create Labels
myLabel_Status_T = Label(root, text="Total time elapsed (hrs:min:sec):")
myLabel_Timer = Label(root, text="00:00:00")
#Locate labels
myLabel_Status_T.grid(row=0, column=0)
myLabel_Timer.grid(row=1, column=0)
Timer_id = None # used to store the ID returned by .after()
#Start button function
def Click_Start():
#disable Start Button to prevent re-start
myButton_Start.config(state=DISABLED)
#enable Stop Button
myButton_Stop.config(state=NORMAL)
#save the start timer
start_time = time.time()
#Timer function
def Timer():
global Timer_id
#determine the amount of time passed since start_time measured
elapsed = int(time.time()-start_time)
minutes, seconds = divmod(elapsed, 60)
hours, minutes = divmod(minutes, 60)
myLabel_Timer.config(text=f"{hours:02}:{minutes:02}:{seconds:02}")
#after 1000 ms repeat the Timer function
Timer_id = root.after(1000,Timer) # save the after ID
Timer()
#Stop button function
def Click_Stop():
if Timer_id:
root.after_cancel(Timer_id) # cancel the scheduled task
#disable Stop Button to prevent re-use until program is reset
myButton_Stop.config(state=DISABLED)
#enable Start Button
myButton_Start.config(state=NORMAL)
#Create Buttons
myButton_Start = Button(root,text="Start CNT Synthesis", padx=40, pady=20,
fg="white", bg="green", command=Click_Start)
myButton_Stop = Button(root,text="Stop CNT Synthesis", padx=40, pady=20,
fg="white", bg="red", command=Click_Stop, state=DISABLED) # disable stop button initially
#Locate buttons
myButton_Start.grid(row=2, column=0)
myButton_Stop.grid(row=2, column=1)
root.mainloop()
Miss the global statement:
def Click_Stop():
global Timer_continue
Timer_continue = False

How to add time (ticks) in a GUI for a game

I want to add the ticking of time in seconds to a GUI, for a clicker game. So the idea is to have a function that gets called every n ticks, and this function increments X objects.
I have tried to use a while loop, both before and after calling the .mainloop() method. It didn't work in either occasion, I also tried the crazy idea of having the mainloop() method inside the while loop (aware of what that would do lol).
from tkinter import *
import time
result = 0
window = Tk()
window.title("Numbers Game")
window.geometry('360x240')
label = Label(window, text=result)
label.grid(column=0,row=0)
def clicked():
global result
result += 1
label.config(text=result)
button = Button(window, text="Push Me", command=clicked)
button.grid(column=1, row=2)
window.mainloop()
while True:
time.sleep(1)
clicked()
The current version of my code produces an error that mentions the function doing GUI related things outside of the window. But I don't have the slightest clue of how to achieve this.
You mean you want to have the result counter increment every second? You can't use infinite loops with a GUI, because they interfere with the GUI's mainloop. You have to integrate your code into the mainloop using the after method.
from tkinter import *
import time
result = 0
window = Tk()
window.title("Numbers Game")
window.geometry('360x240')
label = Label(window, text=result)
label.grid(column=0,row=0)
def clicked():
global result
result += 1
label.config(text=result)
def tick():
clicked()
window.after(1000, tick) # after 1,000 milliseconds, call tick() again
button = Button(window, text="Push Me", command=clicked)
button.grid(column=1, row=2)
tick() # start the "loop"
window.mainloop()

How do I start a timer when I click on an entry widget

I'm trying to start a timer when I click on an entry widget, but I have no clue how to do it.
I've got a program that loads up a tk window, and a timer starts as soon as the window opens. I have a button that resets the timer, but I would like to have it so that the timer starts only when I click inside the entry box.
I've also got a bind setup so that when I hit enter the text is passed into a function and printed.
from tkinter import *
from tkinter import messagebox
counter = 0
def counterlabel(label):
def count():
global counter
counter += 1
label.config(text=str(counter))
label.after(1000, count)
count()
def game(*args):
x = entry.get()
print(x)
def reset(label):
global counter
counter = 0
label.config(text=str(counter))
root = Tk()
root.title("hello")
quit = Button(root, command=lambda: root.destroy())
quit.pack()
label = Label(root)
label.pack()
button = Button(
root, text="hit me to reset timer",
command=lambda: reset(label))
button.pack()
entry = Entry(root)
entry.bind("<Return>", game)
entry.pack()
counterlabel(label)
root.mainloop()
Why not bind Entry widget with <Button-1> sequence with counter, So when a user clicks on the Entry widget the timer starts and the rest is as you've programmed.
Try this:
entry.bind( "<Button-1>",lambda e: counterlabel(label) )
Also I don't know why you made this function so complicated, when you could've just made one function instead of one inside one, in case if you have other plans to add more code in the functions later.
Could be just this
def count(evt=None):
global counter
counter += 1
label.config(text=str(counter))
label.after(1000, count)
...
root=Tk()
...
entry.bind( "<Button-1>", count) )
To stop the timer when you press the button
For that you have to get an id of the after() function and pass it to after_cancel(id) function ( id = after(1000, count) ). It will start again when you click on the Entry.
Here is the complete code
from tkinter import *
from tkinter import messagebox
counter = 0
timer_id = None
def count(evt=None):
global counter, timer_id
entry.unbind('<Button-1>') # So the timer won't go crazy on multiple presses.
counter += 1
label.config(text=str(counter))
timer_id = label.after(1000,count)
def game(*args):
x=entry.get()
print(x)
def reset(label):
global counter
counter=0
if timer_id: label.after_cancel(timer_id)
entry.bind('<Button-1>', count) # When reset the user can start again
label.config(text=str(counter))
root=Tk()
root.title("hello")
quit=Button(root,command=lambda: root.destroy())
quit.pack()
label=Label(root, text='0')
label.pack()
button=Button(root,text="hit me to reset timer",command=lambda: reset(label))
button.pack()
entry=Entry(root)
entry.bind("<Return>", game)
entry.bind('<Button-1>', count)
entry.pack()
root.mainloop()
Hope this helped

Categories

Resources