I would like to ask how would I go about maybe creating a 'LIVE' text box in python? This program is a simulator for a vending machine (code below). I want there to be a text box showing a live credit update How do you do that in tkinter?
For Example: Say there is a box for credit with 0 inside it in the middle of the window. When the 10p button is pressed the box for credit should change from '0' to '0.10'.
Is it possible to do thit in tkinter and python 3.3.2?
Thank you in advance!
import sys
import tkinter as tk
credit = 0
choice = 0
credit1 = 0
coins = 0
prices = [200,150,160,50,90]
item = 0
i = 0
temp=0
n=0
choice1 = 0
choice2 = 0
credit1 = 0
coins = 0
prices = [200,150,160,50,90]
item = 0
i = 0
temp=0
n=0
choice1 = 0
choice2 = 0
def addTENp():
global credit
credit+=0.10
def addTWENTYp():
global credit
credit+=0.20
def addFIFTYp():
global credit
credit+=0.50
def addPOUND():
global credit
credit+=1.00
def insert():
insert = Tk()
insert.geometry("480x360")
iLabel = Label(insert, text="Enter coins.[Press Buttons]").grid(row=1, column=1)
tenbutton = Button(insert, text="10p", command = addTENp).grid(row=2, column=1)
twentybutton = Button(insert, text="20p", command = addTWENTYp).grid(row=3, column=1)
fiftybutton = Button(insert, text="50p", command = addFIFTYp).grid(row=4, column=1)
poundbutton = Button(insert, text="£1", command = addPOUND).grid(row=5, column=1)
insert()
Sure you can! Just add another label to the frame, and update the text attribute whenever one of your add functions is called. Also, you can simplify that code, using one add function for all the different amounts.
def main():
frame = Tk()
frame.geometry("480x360")
Label(frame, text="Enter coins.[Press Buttons]").grid(row=1, column=1)
display = Label(frame, text="") # we need this Label as a variable!
display.grid(row=2, column=1)
def add(amount):
global credit
credit += amount
display.configure(text="%.2f" % credit)
Button(frame, text="10p", command=lambda: add(.1)).grid(row=3, column=1)
Button(frame, text="20p", command=lambda: add(.2)).grid(row=4, column=1)
Button(frame, text="50p", command=lambda: add(.5)).grid(row=5, column=1)
Button(frame, text="P1", command=lambda: add(1.)).grid(row=6, column=1)
frame.mainloop()
main()
Some more points:
note that you define many of your variables twice
you should not give a variable the same name as a function, as this will shadow the function
probably just a copy paste error, but you forgot to call mainloop and your tkinter import is inconsistent with the way you use the classes (without tk prefix)
you can do the layout right after creating the GUI elements, but note that in this case not the GUI element will be bound to the variable, but the result of the layouting function, which is None
Borrowing a framework from tobias_k's excellent answer, I would recommend you use a DoubleVar instead.
from tkinter import ttk
import tkinter as tk
def main():
frame = Tk()
frame.geometry("480x360")
credit = tk.DoubleVar(frame, value=0)
# credit = tk.StringVar(frame, value="0")
ttk.Label(frame, textvariable = credit).pack()
def add_credit(amt):
global credit
credit.set(credit.get() + amt)
# new_credit = str(int(credit.get().replace(".",""))+amt)
# credit.set(new_credit[:-2]+"."+new_credit[-2:])
ttk.Button(frame, text="10p", command = lambda: add_credit(0.1)).pack()
# ttk.Button(frame, text="10p", command = lambda: add_credit(10)).pack()
ttk.Button(frame, text="20p", command = lambda: add_credit(0.2)).pack()
# ttk.Button(frame, text="20p", command = lambda: add_credit(20)).pack()
ttk.Button(frame, text="50p", command = lambda: add_credit(0.5)).pack()
# ttk.Button(frame, text="50p", command = lambda: add_credit(50)).pack()
ttk.Button(frame, text="P1", command = lambda: add_credit(1.0)).pack()
# ttk.Button(frame, text="P1", command = lambda: add_credit(100)).pack()
frame.mainloop()
The comments in that code is an alternate implementation that will work better, if only just. This will guarantee you won't have any strange floating-point errors in your code.
Related
So, I have been trying to create a simple stopwatch in tkinter in which I created a loop to update text to new time i.e., the next second in timer label as I click button_1. I tried to do this with StringVar() as well as .config method but none of them are updating the text in label. The code is below
from datetime import *
from time import *
init_time = datetime(100, 1, 1, 0, 0, 0)
running = True
def clock():
while running == True:
sleep(1)
global init_time
a = init_time.strftime("%H:%M:%S")
mtime.set(a)
init_time = init_time + timedelta(seconds=1)
def stop():
global running
running = False
main = Tk()
main.geometry("500x200")
mtime = StringVar()
timer = Label(main, textvariable = mtime, width=30, bg="black", fg="white", font=(25))
timer.place(x=90, y=20)
button_1 = Button(main, text = "Start", command = clock()).place(x=170, y=120)
button = Button(main, text = "Stop", command = stop).place(x=250, y=120)
main.mainloop()
I even tried to convert the init_time to a string because I thought maybe the updates of text work only for strings. The initial GUI window shows but as I click button_1 it doesn't work.
You did common mistake, look at these two lines
button_1 = Button(main, text = "Start", command = clock()).place(x=170, y=120)
button = Button(main, text = "Stop", command = stop).place(x=250, y=120)
Note that you have clock() and stop. First is function invocation, second is function. You should provide function as command. Replace clock() using clock.
Also if you are interested in executing function every n miliseconds, please take look at .after, consider following simple timer
import tkinter as tk
elapsed = 0
def update_timer():
global elapsed
elapsed += 1
timer['text'] = str(elapsed)
root.after(1000, update_timer) # 1000 ms = 1 second
root = tk.Tk()
timer = tk.Label(root, text="0")
btn = tk.Button(root, text="Go", command=update_timer)
timer.pack()
btn.pack()
root.mainloop()
Im writing a program so i can practise my spanish grammer. I come from the world of PLC programming and wanted to delve into Python to get 2 birds stoned at once. Below is the code, it however gives me an error on the syntax as its missing the var RandomVerbNumber in the on_change def. I have tried defining it outside of the def structures, but it will always make RandomVerbNumber have an incorrect value.
I have tried looking into classes and the init function. But that's not very clear to me yet.
import gspread
import random
import tkinter as tk
gc = gspread.service_account(filename = 'credentials.json')
SpanishVerbs = gc.open('Spanish Verbs')
worksheet = SpanishVerbs.worksheet("EnglishSpanishList")
EnglishList = worksheet.col_values(1)
SpanishList = worksheet.col_values(2)
AmountOfRows = len(worksheet.col_values(1))
def on_next(event):
RandomVerbNumber = random.randint(0,AmountOfRows)
EnglishVerbLabel.config(text = EnglishList[RandomVerbNumber])
print(EnglishList[RandomVerbNumber]," = ",SpanishList[RandomVerbNumber])
def on_change(event):
if SpanishEntry.get() == SpanishList[RandomVerbNumber]:
ResultLabel.config(text = "Correct")
else:
ResultLabel.config(text = "Incorrect")
SpanishEntry.delete(0, tk.END)
root = tk.Tk()
QuestionLabel = tk.Label(root, text = "Spanish Verb for:")
EnglishVerbLabel = tk.Label(root)
ResultLabel = tk.Label(root)
SpanishEntry = tk.Entry(root)
root.bind("<Return>", on_change)
buttonNext = tk.Button(root, text="Next", fg="black")
buttonNext.bind("<Button-1>", on_next)
QuestionLabel.grid(row=0, sticky=tk.E)
EnglishVerbLabel.grid(row=0, column=1)
SpanishEntry.grid(row=1, columnspan=2)
buttonNext.grid(row=2, columnspan=2)
ResultLabel.grid(row=3, columnspan=2)
root.mainloop()
RandomVerbNumber is not defined in the function on_change. Why do you think it would be defined?
There does exist a variabel RandomVerbNumber in another function, but that's outside of the scope of on_change. Variables only exists within their scope.
You can pass a randomised array defined in main as an argument into both methods, holding the index values of the words and pop the index value in the on_next method. Your edited code is below, my edits are marked with NOTE tags.
This method works because python lists are passed by reference.
import gspread
import random
import tkinter as tk
gc = gspread.service_account(filename = 'credentials.json')
SpanishVerbs = gc.open('Spanish Verbs')
worksheet = SpanishVerbs.worksheet("EnglishSpanishList")
EnglishList = worksheet.col_values(1)
SpanishList = worksheet.col_values(2)
AmountOfRows = len(worksheet.col_values(1))
#NOTE:
randomisedList = random.sample(range(AmountOfRows), AmountOfRows)
#NOTE: event argument removed
def on_next(list):
EnglishVerbLabel.config(text = EnglishList[RandomVerbNumber])
print(EnglishList[RandomVerbNumber]," = ",SpanishList[RandomVerbNumber])
list.pop()
#NOTE: event argument removed
def on_change(list):
#NOTE:
if SpanishEntry.get() == SpanishList[list[-1]]:
ResultLabel.config(text = "Correct")
else:
ResultLabel.config(text = "Incorrect")
SpanishEntry.delete(0, tk.END)
root = tk.Tk()
QuestionLabel = tk.Label(root, text = "Spanish Verb for:")
EnglishVerbLabel = tk.Label(root)
ResultLabel = tk.Label(root)
SpanishEntry = tk.Entry(root)
#NOTE:
root.bind("<Return>", lambda event, list=randomisedList: on_change(list))
buttonNext = tk.Button(root, text="Next", fg="black")
#NOTE:
buttonNext.bind("<Button-1>", lambda event, list=randomisedList: on_next(list))
QuestionLabel.grid(row=0, sticky=tk.E)
EnglishVerbLabel.grid(row=0, column=1)
SpanishEntry.grid(row=1, columnspan=2)
buttonNext.grid(row=2, columnspan=2)
ResultLabel.grid(row=3, columnspan=2)
root.mainloop()
I have a off delay program in which when I select the input checkbutton, the output is 1. When I deselect the input checkbutton, the output goes back to 0 after a timer (set up in a scale). For that I use the after method. That part works. My problem is that I want to reset the timer if the checkbutton is selected again before the output went to 0; but once the checkbutton is selected the first time, the after method get triggered and it doesn't stop. I'm trying to use after_cancel, but I can't get it to work. Any solution?
from tkinter import *
root = Tk()
t1= IntVar()
out = Label(root, text="0")
remain_time = IntVar()
grab_time = 1000
def start_timer(set_time):
global grab_time
grab_time = int(set_time) * 1000
def play():
if t1.get() == 1:
button1.configure(bg='red')
out.configure(bg="red", text="1")
else:
button1.configure(bg='green')
def result():
out.configure(bg="green", text="0")
out.after(grab_time,result)
button1 = Checkbutton(root,variable=t1, textvariable=t1, command=play)
time = Scale(root, from_=1, to=10, command=start_timer)
button1.pack()
time.pack()
out.pack()
root.mainloop()
Expected: when press the checkbutton before the output went to 0, reset the counter.
So you could use the .after_cencel when the value of checkbutton is 1:
from tkinter import *
root = Tk()
t1= IntVar()
out = Label(root, text="0")
remain_time = IntVar()
grab_time = 1000
def start_timer(set_time):
global grab_time
grab_time = int(set_time) * 1000
def play():
if t1.get() == 1:
button1.configure(bg='red')
out.configure(bg="red", text="1")
try: # when the first time you start the counter, root.counter didn't exist, use a try..except to catch it.
root.after_cancel(root.counter)
except :
pass
else:
button1.configure(bg='green')
def result():
out.configure(bg="green", text="0")
root.counter = out.after(grab_time,result)
button1 = Checkbutton(root,variable=t1, textvariable=t1, command=play)
time = Scale(root, from_=1, to=10, command=start_timer)
button1.pack()
time.pack()
out.pack()
root.mainloop()
I can't generate the number because I get the error NameError: name 'z' is not defined.
import tkinter as tk
from random import randint
def randomize():
z.set ( randint(x.get(),y.get()))
root = tk.Tk()
x = tk.IntVar()
y = tk.IntVar()
text= tk.Label(root, text = "press the button for random number")
enterX = tk.Entry(root)
enterY = tk.Entry(root)
button = tk.Button(root, text = "Press here", command=randomize)
result = tk.Label(root,text="Number is:")
number = tk.Label(root, textvariable=z)
text.pack()
enterX.pack()
enterY.pack()
button.pack()
result.pack()
number.pack()
root.mainloop()
I need help to resolve the error
You have 2 problems here.
One. You are missing z = tk.Intvar() in the global namespace.
Two. You need to assign each entry field one of the IntVar()'s.
Keep in mind that you are not validating the entry fields so if someone types anything other than a whole number you will run into an error.
Take a look at this code.
import tkinter as tk
from random import randint
def randomize():
z.set(randint(x.get(),y.get()))
print(z.get()) # added print statement to verify results.
root = tk.Tk()
x = tk.IntVar()
y = tk.IntVar()
z = tk.IntVar() # added IntVar()
text= tk.Label(root, text = "press the button for random number")
enterX = tk.Entry(root, textvariable=x) # added textvariable
enterY = tk.Entry(root, textvariable=y) # added textvariable
button = tk.Button(root, text = "Press here", command=randomize)
result = tk.Label(root,text="Number is:")
number = tk.Label(root, textvariable=z)
text.pack()
enterX.pack()
enterY.pack()
button.pack()
result.pack()
number.pack()
root.mainloop()
So I am writing a Python program in class that uses the Caesar cipher to take a users input and output it as cipher-text. Since i had a lot more time for this project I planned on giving it a GUI in Tkinter. But when I assign the resulted cipher-text to a label it won't display it and keeps it blank. I'm a noob to python and even more to Tkinter so I'm not too keen on being able to fix these issues myself. Here's the code:
import string
import collections
import random
import tkinter
from tkinter import *
from tkinter.ttk import *
root = Tk()
root.title("Encoder")
root.geometry("500x400")
def caesar(rotate_string, number_to_rotate_by):
upper = collections.deque(string.ascii_uppercase)
lower = collections.deque(string.ascii_lowercase)
upper.rotate(number_to_rotate_by)
lower.rotate(number_to_rotate_by)
upper = ''.join(list(upper))
lower = ''.join(list(lower))
return rotate_string.translate(str.maketrans(string.ascii_uppercase, upper)).translate(str.maketrans(string.ascii_lowercase, lower))
def callback():
print (code)
b = Button(root, text="get", width=10, command=callback)
b.pack()
var = StringVar()
e = Entry(root, textvariable = var)
e.pack()
our_string = e.get()
random_number = random.randint(1,25)
code = caesar(our_string, random_number)
l = Label(root, textvariable=code, anchor=NW, justify=LEFT, wraplength=398)
l.pack()
l.place(relx=0.5, rely=0.5, anchor=CENTER)
root.mainloop()
There are several issues with the code you've posted. First and foremost, your callback doesn't do anything besides print the code variable. You need to move your call to caesar and the associated code into the callback, like so
def callback():
global code
our_string = e.get()
random_number = random.randint(1, 25)
code.set(caesar(our_string, random_number))
The second issue that I see is that you need to use a StringVar as the textvariable argument in your Label constructor in order to get the label to update automatically. When all is said and done, my version of your code looks like
import string
import collections
import random
from tkinter import *
from tkinter.ttk import *
root = Tk()
root.title("Encoder")
root.geometry("500x400")
code = StringVar()
code.set('Hello')
def caesar(rotate_string, number_to_rotate_by):
upper = collections.deque(string.ascii_uppercase)
lower = collections.deque(string.ascii_lowercase)
upper.rotate(number_to_rotate_by)
lower.rotate(number_to_rotate_by)
upper = ''.join(list(upper))
lower = ''.join(list(lower))
return rotate_string.translate(str.maketrans(string.ascii_uppercase, upper)).translate(str.maketrans(string.ascii_lowercase, lower))
def callback():
global code
our_string = e.get()
random_number = random.randint(1, 25)
code.set(caesar(our_string, random_number))
b = Button(root, text="get", width=10, command=callback)
b.pack()
var = StringVar()
e = Entry(root, textvariable=var)
e.pack()
l = Label(root, textvariable=code, anchor=NW, justify=LEFT, wraplength=398)
l.pack()
l.place(relx=0.5, rely=0.5, anchor=CENTER)
root.mainloop()
This seems to do what you'd expect.