I'm trying to make a basic interest income calculator using GUI tkinker in Python. However, after entering all the values, the label at the end doesn't update.
Please note that calculations is just printing the variables for now
import tkinter as tk
frame = tk.Tk()
frame.title("Interest Income Calculator")
frame.geometry('800x450')
label = tk.Label(text="Enter Balance (number, no symbols)")
entry = tk.Entry(fg="Black", bg="White", width=50)
label.pack()
entry.pack()
def update1():
global balance
balance = entry.get()
buttonupdate1 = tk.Button(
text = "Save")
buttonupdate1.pack()
buttonupdate1.config(command = update1())
label2 = tk.Label(text="Enter Standard Interest (percentage but no symbol)")
entry2 = tk.Entry(fg="Black", bg="White", width=50)
label2.pack()
entry2.pack()
def update2():
global sinterest
sinterest = entry2.get()
buttonupdate2 = tk.Button(
text = "Save")
buttonupdate2.pack()
buttonupdate2.config(command = update2())
label3 = tk.Label(text="Enter Bonus Interest (percentage but no symbol)")
entry3 = tk.Entry(fg="Black", bg="White", width=50)
label3.pack()
entry3.pack()
def update3():
global binterest
binterest = entry3.get()
buttonupdate3 = tk.Button(
text = "Save")
buttonupdate3.pack()
buttonupdate3.config(command = update3())
button = tk.Button(
text="Calculate",
width=25,
height=1,
background="white",
foreground="black",
)
button.pack()
calculations = (balance, sinterest, binterest)
label4 = tk.Label(
text = (calculations),
foreground = "black",
background="white",
width=25,
height=10
)
def cont():
label4.pack()
button.config(command=cont())
frame.mainloop()
I've tried so many things, like moving around the functions etc. with no luck. please help
To understand why it doesn't work when we use command = func() we have to understand how passing function as an argument works
When we pass function with parentheses as an argument, we are first calling the function and then giving the returned value as an argument for the method or function we are using. For example
def sum():
return 1 + 1
example1 = sum
example2 = sum()
# -> example1 is a function object
# -> example2 is 2
This is why in your code you have to give your button a function object rather than the return value of the function so it can run the function object when you press the button.
I ran your code with these fixes and noticed it doesn't run. This is because in your code you are defining your variables sinterest, balance and binterest inside your functions and it throws an error because now you don't run the functions when the code runs.
Also you are trying to change values inside tuple, which is impossible since tuples are immutable
calculations = (balance, sinterest, binterest)
You should change it to a list, because you can change the value inside list
calculations = [balance, sinterest, binterest]
(command = function) because you are passing the function not calling the function()
Related
I'm wondering why my radiobutton variable is not returning a value. Kindly see my setup below :
Global declarations of the frame, radiobuttons, template variable and 'Download' button. I placed my radiobuttons in a frame. I commented the set() function here.
root = tk.Tk()
frm_radioButtons = tk.Frame(root)
template = tk.StringVar()
# template.set("m")
rbtn_create_delete = tk.Radiobutton(frm_radioButtons, text="Create/Delete items", font=(
'Arial', 8), variable="template", value="cd")
rbtn_move = tk.Radiobutton(
frm_radioButtons, text="Move items", font=('Arial', 8), variable="template", value="m")
btn_download = tk.Button(frm_radioButtons, text="Download",
font=('Arial', 7), command=generate_template, padx=15)
And created them inside a function below. Tried using global keyword but still not working. This is the main point of entry of this script.
def load_gui():
root.geometry("300x360")
frm_radioButtons.columnconfigure(0, weight=1)
frm_radioButtons.columnconfigure(1, weight=1)
#global rbtn_create_delete
#global rbtn_move
rbtn_move.grid(row=0, column=0)
rbtn_create_delete.grid(row=0, column=1)
btn_download.grid(row=1, column=0)
frm_radioButtons.pack(padx=10, anchor='w')
And here is the generate_template function when the 'Download' button is clicked. Note though, that the "Move items" radiobutton is pre-selected when I run the program even if I set(None).
It doesn't print anything.
def generate_template():
type = template.get()
print(type)
Tried a pretty straightforward code below and still did not work. It returns empty string. Switched to IntVar() with 1 & 2 as values, but only returns 0.
import tkinter as tk
def download():
print(btnVar.get())
root = tk.Tk()
btnVar = tk.StringVar()
rbtn1 = tk.Radiobutton(root, text="Button1", variable="bntVar", value="b1")
rbtn2 = tk.Radiobutton(root, text="Button1", variable="bntVar", value="b2")
rbtn1.pack()
rbtn2.pack()
btn_dl = tk.Button(root, text="Download", command=download)
btn_dl.pack()
root.mainloop()
Been reading here for the same issues but I haven't got the correct solution. Appreciate any help. tnx in advance..
Expected result: get() function return
The value passed to the variable option needs to be a tkinter variable. You're passing it a string.
In the bottom example it needs to be like this:
rbtn1 = tk.Radiobutton(root, text="Button1", variable=btnVar, value="b1")
rbtn2 = tk.Radiobutton(root, text="Button1", variable=btnVar, value="b2")
# ^^^^^^
Using Tkinter and Python. Already created a window for the buttons to be placed on. I want there to be four buttons to appear, and I want to be able to click one of the four buttons, and be able for it to set the selection variable = "whatever I clicked", so that I can then use this variable later to call an API. When I run the program and click on the "General knowledge" button and print the selection, it does correctly print "General knowledge", but then when I try to return this selection variable it just doesn't work and I don't know why.
def select1():
selection = "General Knowledge"
print(selection)
def select2():
selection = "Science"
def select3():
selection = "Entertainment"
def select4():
selection = "Miscellaneous"
button1 = tk.Button(text = "General Knowledge", command = select1)
button1.place(x=100, y=100)
button2 = tk.Button(text = "Science", command = select2)
button2.place(x=100, y=140)
button3 = tk.Button(text = "Entertainment", command = select3)
button3.place(x=100, y=180)
button4 = tk.Button(text = "Miscellaneous", command = select4)
button4.place(x=100, y=220)
There are several ways to accomplish your goal.
One way is to write a single function that will take a value to assign to your variable. This way you can have as many buttons as you like and only a single function.
Not if you are using functions you have to either pass the variable to the function or let the function know it is in the global namespace.
import tkinter as tk
root = tk.Tk()
selection = ''
def assign_value(value):
global selection
selection = value
lbl["text"] = value
print(selection)
lbl = tk.Label(root, text='Selection Goes Here')
lbl.grid(row=0, column=0)
tk.Button(text="General Knowledge", command=lambda: assign_value("General Knowledge")).grid(row=1, column=0)
tk.Button(text="Science", command=lambda: assign_value("Science")).grid(row=2, column=0)
tk.Button(text="Entertainment", command=lambda: assign_value("Entertainment")).grid(row=3, column=0)
tk.Button(text="Miscellaneous", command=lambda: assign_value("Miscellaneous")).grid(row=4, column=0)
root.mainloop()
Or you can assign the value directly from the button.
import tkinter as tk
root = tk.Tk()
selection = tk.StringVar()
selection.set('Selection Goes Here')
lbl = tk.Label(root, textvariable=selection)
lbl.grid(row=0, column=0)
tk.Button(text="General Knowledge", command=lambda: selection.set("General Knowledge")).grid(row=1, column=0)
tk.Button(text="Science", command=lambda: selection.set("Science")).grid(row=2, column=0)
tk.Button(text="Entertainment", command=lambda: selection.set("Entertainment")).grid(row=3, column=0)
tk.Button(text="Miscellaneous", command=lambda: selection.set("Miscellaneous")).grid(row=4, column=0)
root.mainloop()
I am sure if I spent more time on this I could think up something else but the idea is basically write your code in a more DRY (Don't Repeat Yourself) fashion and make sure you are assigning the value to the variable in the global namespace or else it will not work as you expect.
There's an example of my code below.
I am trying to make a GUI with tkinter, in python. I want an app that has a variable, let's say var_list, that is introduced into a function as a parameter.I run this function using a button with command=lambda: analize(var_list)
I want to be able to modify the variable by pressing buttons (buttons to add strings to the list). And I have a function for that aswell:
def button_clicked(e):
if ((e["text"]).lower()) in var_list:
var_list.pop(var_list.index((e["text"]).lower())) #this adds a string to the list
else:
var_list.append((e["text"]).lower()) #this deletes the string from the list if it was already there
The function works, I tried printing the var_list and it gets updated everytime I press a button.
The problem is that I have to create the var_list as an empty list before, and when I run the function analize(var_list), it uses the empty list instead of the updated one.
Any idea on how to update the global var everytime I add/delete something from the list?
from tkinter import *
from PIL import ImageTk
def show_frame(frame):
frame.tkraise()
def button_clicked(e):
if ((e["text"]).lower()) in var_list:
var_list.pop(var_list.index((e["text"]).lower()))
else:
var_list.append((e["text"]).lower())
def analize(x):
#does stuff with the list
window = Tk()
frame1 = Frame(window)
frame2 = Frame(window)
canvas1 = Canvas(frame1,width = 1280, height = 720)
canvas1.pack(expand=YES, fill=BOTH)
image = ImageTk.PhotoImage(file="background.png")
var_list = []
button1 = Button(canvas1, text="Analize",font=("Arial"),justify=CENTER, width=10, command=lambda: [show_frame(frame2),analize(x=var_list)])
button1.place(x=(1280/2)-42, y=400)
button2 = Button(canvas1, text="String1",font=("Arial"),justify=CENTER, width=10, command=lambda: button_clicked(button2))
button2.place(x=(1280/2)-42, y=450)
button3 = Button(canvas1, text="String2",font=("Arial"),justify=CENTER, width=10, command=lambda: button_clicked(button3))
button3.place(x=(1280/2)-42, y=500)
Thank you
you can make a global variable eg:-global var
Now you can access it within other defination to manipulate the variable like this
global var
var = 0 # if you want to set a default value to the variable before calling the
function
def change_var():
global var
var = 1
USE OF GLOBAL
using global is highly recommended and is quite necessary if you are working with functions that contain or has the need to manipulate the variable
If global is not given inside the function, the variable will live inside the function and it cannot be accessed outside the function.
Hope this answer was helpful, btw, I am not sure if this the answer you are looking for as your question is not clear, maybe give a situation where you might think it might be necessary to change or update the variable
Sorry, I did not understand you but I guess this example will help you -
import tkinter as tk
root = tk.Tk()
var_list = []
def change_val(n):
var_list.append(n)
label1.config(text=var_list)
def remove():
try:
var_list.pop()
label1.config(text=var_list)
except:
pass
label1 = tk.Label(root,text=var_list)
label1.pack()
button1 = tk.Button(root,text='1',command=lambda:change_val(1))
button1.pack()
button2 = tk.Button(root,text='2',command=lambda:change_val(2))
button2.pack()
button3 = tk.Button(root,text='3',command=lambda:change_val(3))
button3.pack()
button4 = tk.Button(root,text='Pop Element',command=remove)
button4.pack()
root.mainloop()
When I run this code is says "UserName is not defined even" though its defined in the function right below it. Do the functions have to be a certain order and if so is there a way to fix that.
from tkinter import *
def MasterLogin():
Name = UserName.get()
Email = RegisterEmail.get()
Password = RegisterPassword.get()
MasterLogin = Tk()
MasterLogin.title('Login')
MasterLogin.geometry('260x100')
LoginEmail = Entry(MasterLogin, width=30).grid(row=0, column=1)
LoginEmailText = Label(MasterLogin, text=Email).grid(row=0, column=0)
def MasterRegister():
MasterRegister = Tk()
MasterRegister.title('Register')
MasterRegister.geometry('260x100')
UserName = Entry(MasterRegister, width=30).grid(row=0, column=1)
UserNameText = Label(MasterRegister, text='Name ').grid(row=0, column=0)
RegisterEmail = Entry(MasterRegister, width=30).grid(row=1, column=1)
RegisterEmailText = Label(MasterRegister, text='Email ').grid(row=1, column=0)
RegisterPassword = Entry(MasterRegister, width=30).grid(row=2, column=1)
RegisterPasswordText = Label(MasterRegister, text='Password ').grid(row=2, column=0)
RegisterCont = Button(MasterRegister, text='Continue', width=25, bg='blue', fg='white',
command=MasterLogin).grid(row=3, column=1)
When looking at this code I would suggest the following. Create a class that handles windows. In this, you can easily have functions that do what you need to do, in this code it seems you are using functions as the end all be all for your code, this would be inefficient for your code and not very future proof.
Without a class you can still achieve what you want for an Entry box, the issues here with your example is that your variables are declared along a private scope making them inaccessible to the rest of the program, this can be fixed with declaring global within a certain area of your code but this can become messy and render functions almost useless for private functionality (this can lead to many errors)
Heres my simple example for an entry box with a button that gets the data in it
from tkinter import *
def ButtonPress(entry):
entry = entry
print(entry.get())
return entry.get()
F = Tk()
F.geometry("300x100")
F.config(bg="black")
myEntry = Entry()
myEntry.pack()
myButton = Button(text="Enter",command=lambda : ButtonPress(myEntry))
myButton.pack()
F.mainloop()
I am popping up a custom dialog box using Tkinter.
I am opening it from another Tkinter window.
root = Tk()
class ListDialog:
def __init__(self, names, prompt):
self.names = names
self.sub_root = Tk()
self.sub_root.title("Intovex")
self.sub_root.iconbitmap("Icon.ico")
self.myfont = Font(root=self.sub_root, family="Arial", size=8)
self.sub_root.maxsize(320, 240)
self.sub_root.wm_attributes("-topmost", True)
self.sub_root.wm_attributes("-toolwindow", True)
self.var = IntVar()
label = Label(self.sub_root, text=prompt)
label.pack(fill=X)
c=1
print(names)
for i in names:
print(i)
r = Radiobutton(self.sub_root, text=i, variable=self.var, value=c, command=self.end)
r.pack(anchor=W)
c+=1
self.var.set(1)
button = Button(self.sub_root, command=self.endit, text="OK", bg = "#448DE0", fg="White", bd=0, width=12, pady=4, padx=4, height=1,font=self.myfont, highlightcolor="#A3C7F0")
button.pack(side=BOTTOM)
self.choice = names[0]
def end(self):
ch = self.var.get()
print(str(ch))
self.choice = self.names[ch - 1]
def endit(self):
self.sub_root.destroy()
def ask(self):
self.sub_root.mainloop()
var2 = StringVar()
def get_choice():
list = ListDialog(["Test1", "Test2"], "Testing")
list.ask()
var2.set(str(list.choice))
label = Label(root, text="", textvariable=var2)
button = Button(root, text="Test", command=get_choice)
label.pack()
button.pack()
root.mainloop()
However, it works when it is run alone by directly instantiating the class and invoking ask() method.
You may have seen that I have print statements everywhere in the code(it is for debugging) and I found where isn't it working
The print statement to print the names list parameter is printing the whole list correctly.
Inside the for-loop also it prints the elements in the names list correctly
When I click on a radio button it invokes the end() method. There it always prints the default value.
root = Tk()
class ListDialog:
def __init__(self, names, prompt):
self.names = names
self.sub_root = Tk()
self.sub_root.title("Intovex")
self.sub_root.iconbitmap("Icon.ico")
self.myfont = Font(root=self.sub_root, family="Arial", size=8)
self.sub_root.maxsize(320, 240)
self.sub_root.wm_attributes("-topmost", True)
self.sub_root.wm_attributes("-toolwindow", True)
self.var = IntVar()
label = Label(self.sub_root, text=prompt)
label.pack(fill=X)
c=1
print(names)
for i in names:
print(i)
r = Radiobutton(self.sub_root, text=i, variable=self.var, value=c, command=self.end)
r.pack(anchor=W)
c+=1
self.var.set(1)
button = Button(self.sub_root, command=self.endit, text="OK", bg = "#448DE0", fg="White", bd=0, width=12, pady=4, padx=4, height=1,font=self.myfont, highlightcolor="#A3C7F0")
button.pack(side=BOTTOM)
self.choice = names[0]
def end(self):
ch = self.var.get()
print(str(ch))
self.choice = self.names[ch - 1]
def endit(self):
self.sub_root.destroy()
def ask(self):
self.sub_root.mainloop()
list = ListDialog(["Test1", "Test2"], "Testing")
list.ask()
print(list.choice)
But it works if I open it as a TopLevel widget. But then the main window doesn't wait till the popup windows returns the value(choice).
The problem with the code in the first snippet is because you're calling Tk() more that once within the tkinter application — it confuses the interface code and can cause a variety of problems, as you're finding out.
If you replace the call inside the __init__() method of the ListDialog class, with one to tk.Toplevel() instead, then your code will start working.
I also streamlined the for loop that creates the Radiobuttons by changing it so to use the built-in enumerate() function to automatically keep a count of the names. In conjunction with that, I made the initial value of the IntVar zero which is not one of the values that selecting one the radiobuttons will assign it. This is so when the ListDialog is first displayed, none of them will be selected. It also ensures that the end() callback function will get called whenever the user presses one of them, so your app will always be informed when that happens.
Note that, although I didn't change it, you shouldn't name a variable list because that hides the name of the built-in class by that name. In general you should avoid naming anything something that conflicts with an existing standard Python name.
from tkinter import *
from tkinter.font import Font
root = Tk()
class ListDialog:
def __init__(self, names, prompt):
self.names = names
# self.sub_root = Tk() # Wrong - don't call Tk() more than once.
root.withdraw() # Hide root window.
self.sub_root = Toplevel() # Create another top-level window.
self.sub_root.title("Intovex")
# self.sub_root.iconbitmap("Icon.ico") # I don't have this file...
self.myfont = Font(root=self.sub_root, family="Arial", size=8)
self.sub_root.maxsize(320, 240)
self.sub_root.wm_attributes("-topmost", True)
self.sub_root.wm_attributes("-toolwindow", True)
self.var = IntVar(value=0) # Define and init value to one *not* produced by btns.
label = Label(self.sub_root, text=prompt)
label.pack(fill=X)
print(names)
for c, name in enumerate(names, start=1):
print(c)
r = Radiobutton(self.sub_root, text=c, variable=self.var, value=c,
command=self.end)
r.pack(anchor=W)
button = Button(self.sub_root, command=self.endit, text="OK", bg = "#448DE0",
fg="White", bd=0, width=12, pady=4, padx=4, height=1,
font=self.myfont, highlightcolor="#A3C7F0")
button.pack(side=BOTTOM)
self.choice = names[0]
def end(self):
ch = self.var.get()
print(str(ch))
self.choice = self.names[ch - 1]
def endit(self):
self.sub_root.destroy()
root.deiconify() # Reshow root window.
def ask(self):
self.sub_root.mainloop()
var2 = StringVar()
def get_choice():
list = ListDialog(["Test1", "Test2"], "Testing")
list.ask()
var2.set(str(list.choice))
label = Label(root, text="", textvariable=var2)
button = Button(root, text="Test", command=get_choice)
label.pack()
button.pack()
root.mainloop()