In python 2.7, I want to print the price of a place depending on the given user input of people. The price should vary each time the user input a different amount of people.
from Tkinter import *
top = Tk()
top.geometry("500x500")
a = Label(text="Adult:")
a.place(x=50,y=100)
adult_input = Entry(top)
adult_input.place(x=100,y=100)
adult_num = Label (text="x RM 5.00 per pax :")
adult_num.place(x=250,y=100)
top.mainloop()
How should I go about printing the the price depending on the user input?
Here is the simplest solution for your situation. Add the following lines just before top.mainloop():
b = Button(top,
text="Confirm",
command=lambda: adult_num.config(text=adult_input.get()))
b.place('''anywhere''')
This will update your adult_num label when clicking the button.
If this is not enough, and you need to compute a value before displaying it, then you'll need a function.
Suppose you have an f function:
def f(adults_number):
adults_number = int(adults_number)
return '''the result of some formula'''
Then you'll have to call it in the button's command:
b = Button(top,
text="Confirm",
command=lambda: adult_num.config(text=str(f(adult_input.get()))))
Also, your adult_num label should be attached to top, so the declaration should be:
adult_num = Label(top, text="...")
You can use Button to execute function which will calculate value
import Tkinter as tk
# --- functions ---
def recalc():
value = e.get()
if value != '':
l['text'] = float(value) * 5.00
# --- main ---
root = tk.Tk()
e = tk.Entry(root)
e.pack()
e.bind('<KeyRelease>', recalc)
l = tk.Label(root)
l.pack()
b = tk.Button(root, text="Recalc", command=recalc)
b.pack()
root.mainloop()
or you can bind event to Entry and it will be calculated after every key.
import Tkinter as tk
# --- functions ---
def recalc(event): # bind executes function with argument `event`
#value = e.get()
value = event.widget.get()
if value != '':
l['text'] = float(value) * 5.00
# --- main ---
root = tk.Tk()
e = tk.Entry(root)
e.pack()
e.bind('<KeyRelease>', recalc)
l = tk.Label(root)
l.pack()
root.mainloop()
Related
I am trying to make a little thing in python like JOpenframe is java and I'm trying to make an entry box. That works fine but when I try to get the value and assign it to variable "t" nothing works. This is what I have:
def ButtonBox(text):
root = Tk()
root.geometry("300x150")
t = Label(root, text = text, font = ("Times New Roman", 14))
t.pack()
e = Entry(root, borderwidth = 5, width = 50)
e.pack()
def Stop():
root.destroy()
g = e.get()
ok = Button(root, text = "OK", command = Stop)
ok.pack()
root.mainloop()
t = ButtonBox("f")
I've tried to make "g" a global variable but that doesn't work. I have no idea how to get the value from this, and I'm hoping someone who does can help me out. Thanks!
If you want to return the value of the entry box after ButtonBox() exits, you need to:
initialize g inside ButtonBox()
declare g as nonlocal variable inside inner function Stop()
call g = e.get() before destroying the window
Below is the modified code:
from tkinter import *
def ButtonBox(text):
g = "" # initialize g
root = Tk()
root.geometry("300x150")
t = Label(root, text = text, font = ("Times New Roman", 14))
t.pack()
e = Entry(root, borderwidth = 5, width = 50)
e.pack()
def Stop():
# declare g as nonlocal variable
nonlocal g
# get the value of the entry box before destroying window
g = e.get()
root.destroy()
ok = Button(root, text = "OK", command = Stop)
ok.pack()
root.mainloop()
# return the value of the entry box
return g
t = ButtonBox("f")
print(t)
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'm trying to build a toplevel window within python that has a single label within it called "text". It's textvariable is called "v". As you can see, there are 3 function calls within dialogueBox(). What I want the program to do is have the label "text" display the phrase "Event one", wait one second, display the phrase "Event two", wait one second, and then display the phrase "Event three". Instead of doing this, the top level window is opened displaying only "Event three".
I suspect that this is a lambda issue but I'm still not sure how to use it in Tkinter.
from tkinter import*
import time
def event1():
v.set("Event one")
def event2():
v.set("Event two")
def event3():
v.set("Event three")
def dialogueBox():
top = Toplevel()
global v
top.minsize(400,0)
top.maxsize(700,300)
top.title("Toplevel test")
v = StringVar()
text = Label(top,textvariable = v)
text.pack()
event1()
time.sleep(1)
event2()
time.sleep(1)
event3()
root = Tk()
email = StringVar()
password = StringVar()
title = Label(root,text="Root window",font = 11)
title.pack()
label1 = Label(root,text = "Username")
label1.pack()
field1 = Entry(root,textvariable = email)
field1.pack()
label2 = Label(root,text = "Password")
label2.pack()
field2 = Entry(root,show = "*",textvariable = password)
field2.pack()
button = Button(root,text = "Get data",command = dialogueBox)
button.pack()
root.mainloop()
You were very close, but your best bet is using the after() method.
Here's your modified code, with comments added:
from tkinter import*
import time
def event1():
v.set("Event one")
root.after(1000, event2) # NEW
def event2():
v.set("Event two")
root.after(1000, event3) # NEW
def event3():
v.set("Event three")
def dialogueBox():
top = Toplevel()
global v
top.minsize(400,0)
top.maxsize(700,300)
top.title("Toplevel test")
v = StringVar()
text = Label(top,textvariable = v)
text.pack()
event1()
#time.sleep(1)
#event2()
#time.sleep(1)
#event3()
root = Tk()
email = StringVar()
password = StringVar()
title = Label(root,text="Root window",font = 11)
title.pack()
label1 = Label(root,text = "Username")
label1.pack()
field1 = Entry(root,textvariable = email)
field1.pack()
label2 = Label(root,text = "Password")
label2.pack()
field2 = Entry(root,show = "*",textvariable = password)
field2.pack()
button = Button(root,text = "Get data",command = dialogueBox)
button.pack()
root.mainloop()
The only real change is employing the after method from event1() to call event2(), and from event2() to call event3(). With these after() calls, the last 4 lines in your dialogueBox() go away.
What is happening? Tkinter is a GUI, event-driven system. It doesn't like sitting there and waiting for anything. While you're sleeping, resources are wasted, and the GUI cannot refresh and update itself. By employing the after() method, the GUI can continue doing what it does best: waiting for events and input. The after() method schedules an event to occur later on. When that time comes, the event gets processed. The first arg to after() is the time delay in ms (milliseconds). The second arg is a function name, to be called after the designated time delay.
Now, I said that after() is your best bet, but there is another way to do this, albeit less "polite." You could add .update() method calls to your dialogueBox(), as follows:
def dialogueBox():
top = Toplevel()
global v
top.minsize(400,0)
top.maxsize(700,300)
top.title("Toplevel test")
v = StringVar()
text = Label(top,textvariable = v)
text.pack()
event1()
text.update() # NEW -- RUDE!
time.sleep(1)
event2()
text.update() # NEW -- RUDE!
time.sleep(1)
event3()
The .update() calls rudely tell the GUI, "Stop everything you're doing and do this for me right now!" This will also allow you to see the event1, event2, event3 messages. But the after() is really the better, proper way to do this.
In event1() use root.after(1000, event2) and it will run event2 one second after event1
And you have to remove sleep() and functions event2() event3() from dialog_box()
import tkinter as tk
# --- functions ---
def event1():
v.set("Event one")
root.after(1000, event2) # run event2 after 1000ms (1s)
def event2():
v.set("Event two")
root.after(1000, event3) # run event3 after 1000ms (1s)
def event3():
v.set("Event three")
root.after(1000, close_it) # run close_it after 1000ms (1s)
def close_it():
top.destroy() # close TopLevel window
def dialogue_box():
global v
global top
top = tk.Toplevel()
top.minsize(400,0)
top.maxsize(700,300)
top.title("Toplevel test")
v = tk.StringVar()
text = tk.Label(top, textvariable=v)
text.pack()
event1() # run event1 at once
# --- main ---
root = tk.Tk()
email = tk.StringVar()
password = tk.StringVar()
title = tk.Label(root, text="Root window", font=11)
title.pack()
label1 = tk.Label(root, text="Username")
label1.pack()
field1 = tk.Entry(root, textvariable=email)
field1.pack()
label2 = tk.Label(root, text="Password")
label2.pack()
field2 = tk.Entry(root, show="*", textvariable=password)
field2.pack()
button = tk.Button(root, text="Get data", command=dialogue_box)
button.pack()
root.mainloop()
See demo of after here, also with itertools "show off"
from tkinter import *
import time
from itertools import cycle
label_iter = cycle(('Event One', 'Event Two', 'Event Three'))
def change_label():
v.set(next(label_iter))
root.after(1000, change_label)
def dialogueBox():
top = Toplevel()
global v
top.minsize(400,0)
top.maxsize(700,300)
top.title("Toplevel test")
v = StringVar()
text = Label(top,textvariable = v)
text.pack()
root.after(1000, change_label)
root = Tk()
email = StringVar()
password = StringVar()
title = Label(root,text="Root window",font = 11)
title.pack()
label1 = Label(root,text = "Username")
label1.pack()
field1 = Entry(root,textvariable = email)
field1.pack()
label2 = Label(root,text = "Password")
label2.pack()
field2 = Entry(root,show = "*",textvariable = password)
field2.pack()
button = Button(root,text = "Get data",command = dialogueBox)
button.pack()
root.mainloop()
I am trying to add a reset button but I can't seem to get it to work. I created a main in order to refer back to it when the button is pressed but no luck. Any ideas?
import sys
from tkinter import *
import math
def main():
def closeWin():
myGui.destroy() #Close Window Function
def kiloFunc():
myText = kiloMent.get() #Kilometers to Miles Fuction
convert = 0.62
miles = myText * convert
finalKilo = Label(text = miles,fg='red',justify='center').place(x=200,y=80)
def mileFunc():
myText2 = mileMent.get() #Miles to Kilometers Function
convertTwo = myText2 // 0.62
finalMile = Label(text = convertTwo, fg = 'red',justify='center').place(x=200,y=170)
myGui = Tk()
kiloMent = IntVar()
mileMent = IntVar()
myGui.title("Distance Converter")
myGui.geometry("450x200+500+200")
myLabel = Label(text="Welcome! Please enter your value then choose your option:",fg="blue",justify='center')
myLabel.pack()
kiloEntry = Entry(myGui, textvariable = kiloMent,justify='center').pack()
kilo2milesButton = Button(text = "Kilometers to Miles!", command = kiloFunc).pack()
mileEntry = Entry(myGui, textvariable = mileMent,justify='center').place(x=130,y=105)
miles2kiloButton = Button(text = "Miles to Kilometers!", command = mileFunc).place(x=150,y=135)
reset = Button(text = "Reset Values!", command = main).place(x=10,y=165)
quit = Button(text="Quit", command = closeWin).place(x=385,y=165)
myGui.mainloop()
main()
By calling main() again, you are simply creating another instance of the GUI. What you should do instead is (if I understand correctly), reset the values of the currently existing GUI. You can use the set() method of the GUI objects.
Does
def reset_values():
kiloMent.set(0)
mileMent.set(0)
reset = Button(text="Reset Values!", command=reset_values).place(x=10, y=165)
do the trick?
Looking at your code more thoroughly, however, there are some other problems there, as well. To start with, I would suggest not creating a Label everytime the user tries to convert a value.
This code should work:
from tkinter import *
def main():
def closeWin():
myGui.destroy() # Close Window Function
def kiloFunc():
finalKilo.set(kiloMent.get() * 0.62) # Kilometers to Miles Fuction
def mileFunc():
finalMile.set(mileMent.get() // 0.62) # Miles to Kilometers Function
def clearFunc():
kiloMent.set("0")
mileMent.set("0")
finalKilo.set("")
finalMile.set("")
myGui = Tk()
kiloMent = IntVar()
mileMent = IntVar()
finalKilo = StringVar()
finalMile = StringVar()
myGui.title("Distance Converter")
myGui.geometry("450x200+500+200")
myLabel = Label(text="Welcome! Please enter your value then choose your option:", fg="blue", justify='center')
myLabel.pack()
kiloEntry = Entry(myGui, textvariable=kiloMent, justify='center')
kiloEntry.pack()
kilo2milesButton = Button(text="Kilometers to Miles!", command=kiloFunc)
kilo2milesButton.pack()
mileEntry = Entry(myGui, textvariable=mileMent, justify='center')
mileEntry.place(x=130, y=105)
miles2kiloButton = Button(text="Miles to Kilometers!", command=mileFunc)
miles2kiloButton.place(x=150, y=135)
kiloLabel = Label(textvariable=finalKilo, fg='red', justify='center')
kiloLabel.place(x=200, y=80)
mileLabel = Label(textvariable=finalMile, fg='red', justify='center')
mileLabel.place(x=200, y=170)
reset = Button(text="Reset Values!", command=clearFunc)
reset.place(x=10, y=165)
quit = Button(text="Quit", command=closeWin)
quit.place(x=385, y=165)
myGui.mainloop()
main()
A few notes about your original code besides the ones that Chuck mentioned:
The math and sys imports were unused.
You were setting variables equal to widget.pack() and widget.place(), which are functions that return None.
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.