How can i update a variable after pressing buttons on tkinter? - python

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()

Related

Label not updating from button

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()

Global Variable Undefined? Can't get label to display global variable from function

This is a little program I am making to learn Python which is a NPC Trait Generator that generates random words from a text file.
My random generator works, but I can't get it to display properly in the label. I currently have pertrait set to global but it doesn't seem to pick up the variable to display in the label? I tried setting up StringVar but I couldn't seem to get that to work properly either.
import tkinter as tk
from tkinter import font
# Random Personality generation from text list
def gen():
global pertrait
pertrait = print(random.choice(open(
'F:\\Desktop\\python\\RandomGenerator py\\CharTraitList.txt').read(
).split()).strip())
root = tk.Tk()
root.title("NPC Trait Generator")
root.geometry("500x200")
frame = tk.Frame(root)
frame.pack()
# define font
fontStyle = font.Font(family='Courier', size=44, weight='bold')
# background image variable and import
paper = tk.PhotoImage(
file='F:\\Desktop\\python\\RandomGenerator py\\papbckgrd.png')
butQuit = tk.Button(frame,
text="Quit",
fg="red",
command=quit)
butQuit.pack(side=tk.LEFT)
ButGen = tk.Button(frame,
text="Generate",
command=gen)
ButGen.pack(side=tk.RIGHT)
# Label generation
Trait1 = tk.Label(root,
compound=tk.CENTER,
text=pertrait,
font=fontStyle)
# image=paper) .pack(side="right")
Trait1.pack()
root.mainloop()
print() doesn’t return a value, and you neglected to call gen()!
Change:
pertrait = print(random.choice(open(
'F:\\Desktop\\python\\RandomGenerator py\\CharTraitList.txt').read(
).split()).strip())
To:
pertrait = random.choice(open(
'F:\\Desktop\\python\\RandomGenerator py\\CharTraitList.txt').read(
).split()).strip()
But really it would be much better t avoid the global - make gen() return the value and assign the result of gen() ot pertrait

tkinter, save the input as variable

I want to use the input value as variable and this is my code.
from tkinter import *
from tkinter import messagebox
window = Tk()
Label(window, text='Cavity number').grid(row=0)
CavNum = StringVar()
for i in range(1,8) :
globals()['L{}_CavNum'.format(i)] = StringVar()
globals()['L{}_CavNum'.format(i)] = Entry(window, textvariable=globals()['L{}_CavNum'.format(i)])
globals()['L{}_CavNum'.format(i)].grid(row=0, column=i)
window.geometry("1200x150")
window.mainloop()
everytime I do print(L1_CavNum), it says "<tkinter.Entry object .!entry>". please tell me what is the problem
You are re-using the same name for the entry widget as you use for StringVar. You could simply change globals()['L{}_CavNum'.format(i)] = StringVar() to globals()['L{}_CavNumSV'.format(i)] = StringVar() and print(L1_CavNum) to print(L1_CavNumSV.get()). However the .get() function will execute when your code runs so you will have to have a button or another event to callback the function.
I would do it like this.
from tkinter import *
def print_vars():
for x in range(len(cavity_string_vars)):
print(cavity_string_vars[x].get())
window = Tk()
Label(window, text='Cavity number').grid(row=0)
cavity_string_vars = []
cavity_entries = []
for i in range(7):
cavity_string_vars.append(StringVar())
cavity_entries.append(Entry(window, textvariable=cavity_string_vars[i]))
cavity_entries[i].grid(row=0, column=i)
print_button = Button(window, text="Print", command=print_vars)
print_button.grid(row=1, column=0)
window.geometry("1200x150")
window.mainloop()
To me associated arrays are much easier than naming each variable even when you program it as you have. Perhaps that is needed for your case.

How can i get input text from an entrybox in Tkinter? [duplicate]

This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 2 years ago.
So i am trying to get an text input for my program but tkinter doesn't seem to register it,
and i don't know what i have done wrong
window = self.newWindow(value)
label = tk.Label(window, text="Intfix to Postfix Convert")
label.place(x=0, y=20)
e1 = tk.Entry(window)
text = e1.get()
e1.place(x=0, y=50)
rezultat = tk.Text(window, width=20, height=3)
rezultat.place(x=0, y=80)
button = tk.Button(window, text="Enter")
button.place(x=127, y=46)
button.bind("<Double-Button-1>", self.passValue(rezultat, text))
My code looks something like this. Everything else is working the self.newWindow(value) is just
a function that creates a new window from the main one
so i said text=e1.get() but i ran the debbuger and it says it is an empty string and i want to pass this text through the function passValue()(a function that passes the value to the controller), i used button.bind() to do that. Is that ok?
I tested it by putting a default value at text like text="My name" and it did pass the value so that should be in order but i don't know why doesn't it get it from the entry box like it should.
I even tried to do e1.insert(0,"some random thing") and text= e1.get() and it did get it so i think there's a problem with the input.
Do i need to use some special kind of input function?
The whole code:
class Gui:
def __init__(self, controller):
self.main = tk.Tk()
self.main.title("DSA Quiz Helper")
self.__controller = controller
def IntFixPostExecute(self, event):
widget = event.widget
selection = widget.curselection()
value = widget.get(selection[0])
self.IntfixPostfixWindow(value)
def mainWindow(self):
self.main.geometry("800x500")
# to do scrollbar
lb = tk.Listbox(self.main, width=50, height=30)
lb.insert(1, "Intfix and Postfix Calculator")
lb.insert(2, "Something else")
lb.bind("<Double-Button-1>", self.IntFixPostExecute)
lb.pack()
def IntfixPostfixWindow(self, value):
window = self.newWindow(value)
label = tk.Label(window, text="Intfix to Postfix Convert")
label.place(x=0, y=20)
e1 = tk.Entry(window)
text = e1.get()
e1.place(x=0, y=50)
rezultat = tk.Text(window, width=20, height=3)
rezultat.place(x=0, y=80)
button = tk.Button(window, text="Enter")
button.place(x=127, y=46)
button.bind("<Double-Button-1>", self.passValue(rezultat, text))
print(text)
def passValue(self, rezultat, value):
returnValue = self.__controller.InfixToPostC(rezultat, value)
rezultat.insert(tk.INSERT, returnValue)
def newWindow(self, msg):
newwind = tk.Toplevel(self.main)
q1 = tk.Frame(newwind)
q1.pack()
newwind.geometry("500x230")
return newwind
def run(self):
self.mainWindow()
self.main.mainloop()
if i set this manually it works. I don't understand why i doesn't work from entrybox input
text = tk.StringVar()
e1 = tk.Entry(window, textvariable=text)
text.set("x+y*2")
text = e1.get()
e1.place(x=0, y=50)
I think i figured it out (correct me if i am wrong). I think there is a problem
with the button because as soon as a newwindow is open, the button automatically clicks itself, when at first in the entry box there is no text written yet(so it sends to the controller with the initial text(which is empty)). The problem is why the button auto-clicks itself( or anyway auto-runs the function passValue) and why after i input the text and click the button again it does nothing(so as i understand it works only one time and auto-runs itself, at first there is no text in entrybox and the button auto-runs itself,therefore passing an empty string
You should use entryname.get() to get the text that is inside that entry instead of declaring stringVar() and making that much more unreadable and hard to comprehend and to work with. But this is my point of view! – Tiago Oliveira 48 mins ago
I think what is happening is that u use the method right after declaring the entry widget wich means u are going to get a "" empty string because that's nothing that was written there, u need to replace on the command parameter with entryname.get() instead of declaring variable = entryname.get() and passing that as parameter wich will always be empty! Hope this helps!

How to pass parameters to functions in python

I have this simple program that I wrote so I could better understand the 'return' function and how to pass a value from one function to another. All this program does is to pass the value of buttontwo=2 to the function button_one_function,so if button two is pressed first then button one does nothing.I thought that I could do this without using a global statement - is there a way of writing the code below without using global? I have tried doing this by putting the value of buttontwo in to the button_one_function parentheses but this didnt work. Thanks for any tips
from tkinter import *
my_window = Tk()
my_frame = Frame(my_window, height=500, width=500, bd='4')
my_frame.grid(row=0, column=0)
def button_one_function():
if button_two == 2:
print('do nothing')
else:
label_one = Label(my_frame, text='label one')
label_one.grid(row=1, column=0, sticky='n')
def button_two_function():
global button_two
button_two = 2
label_two = Label(my_frame, text='label two')
label_two.grid(row=1, column=1, sticky='n')
return button_two
button_one = Button(my_frame, text='button1', command=button_one_function)
button_one.grid(row=0, column=0)
button_two = Button(my_frame, text='button2', command=button_two_function)
button_two.grid(row=0, column=1)
my_window.mainloop()
If I've understood corectly, you are interested in sth. like this:
from tkinter import *
root = Tk()
def click(a):
print(a)
Button(root, text='1', command=lambda: click('1')).pack()
Button(root, text='2', command=lambda: click('2')).pack()
root.mainloop()
What is happening is I'm not passing a full click function to a button, but a so called lambda function, which is essentially a one-line function. Example: if I did p = lambda: print('Hi') then each time I do p() I would see a little Hi pop up. Also, if I did k = lambda a,b: a*b then k(4,5) would return "20". More info about lambdas here.
Hope that's helpful!
def function(a,b):
print("a is :",a)
print("b is :",b)
function(10,20)
You can definitely do this without globals. You could extend the tk.button class to hold a variable like self.status = pressed.
There are a few ways you can go about this with classes. You could create either one or two classes. Maybe even have child classes for each button.
But you can just dump both your functions in one class and pass self as its first argument.
Whenever I feel the need for a global variable, I usually make a class.

Categories