Dynamically changing Label variable - python

What I am trying to do is build a window with a number(default value=1) and
3 buttons underneath it named: "UP","DOWN" and "QUIT". "Up" button is going to increment the number by 1 and the rest of the buttons are clear what they do.
from Tkinter import *
root=Tk()
number=1
Label(root,text=number,height=10,width=7).grid(row=0,pady=10,padx=10,column=10,columnspan=2,sticky=W+E)
def auksisi(number):
number+=1
return number
def meiosi(number):
number = number -1
return number
Label(root, text=auksisi(number),height=10,width=7).grid(row=0,pady=10,padx=10,column=10,columnspan=2,sticky=W+E)
Button(root, text="up",command=lambda: auksisi(number)).grid(row=3,column=2,columnspan=2)
Button(root, text="down",command=lambda: meiosi(number)).grid(row=3,column=3,columnspan=2)
Button(root, text="quit",command=root.destroy).grid(row=3,column=4,columnspan=2)
root.update()
root.mainloop()
What is happening is when I press the buttons nothing changes.Don't worry about the layout I will fix it, I just want the buttons to work.

The grid method returns None, and calling it directly after the creation of your objects, would make your eventual references to be None as well. To change the values of your label, you need a reference to it:
label_reference = Label(root, text=auksisi(number), height=10, width=7)
label_reference.grid(row=0, pady=10, padx=10, column=10, columnspan=2, sticky=W+E)
Now, through label_reference you can change the text using for example the config() method. You can do this in the method that is called when you click your buttons:
def auksisi(number):
number += 1
label_reference.config(text=number)
return number

Related

How can an object refer to itself despite being lost in memory?

I'm making a DBMS in Tkinter and I want to have a button that will delete the corresponding entry (the entry to the right of it). How would the computer know what button is sending the command or is linked to what entry (or how do I link them)
Take a look at the following code
def edit_db():
for i in root.winfo_children():
i.grid_remove()
back_btn = Button(root, text='<--', command=home)
back_btn.place(height=30, width=30, x=4, y=4)
row_count = 1
for i in cur.execute("SELECT * FROM students").fetchall():
save_btn = Button(root, text='Save', font=("Calbri", 9))
if row_count == 1: save_btn.grid(row=row_count, column=1, pady=(45, 3), padx=(5, 10))
else: save_btn.grid(row=row_count, column=1, pady=3, padx=(5, 10))
del_btn = Button(root, text="X", font=("Calbri", 9), command=del_entry)
if row_count == 1: del_btn.grid(row=row_count, column=0, pady=(45, 3), padx=5)
else: del_btn.grid(row=row_count, column=0, pady=3, padx=(5))
As you can see their are multiple del_btn (and save_btn) and their variable names will no longer correspond, but I want do something like
del_btn = Button(root, text="X", font=("Calbri", 9), command=del_entry(**self/this/me**))
Is there something I can do? Do I have to do this all in a class (I'm not very good a OOP so I don't know what difference it would make)? Or am I missing something and their is way to link each button with the entries in the database.
Here is my picture of my app, if it will help
Here is the solution (includes 3 options):
from tkinter import Tk, Button, Label
label_list = []
def destroy_widget(index):
label_list[index].destroy()
root = Tk()
for i in range(10):
lbl = Label(root, text=f'Label {i}')
lbl.grid(row=i, column=0, sticky='nsew')
label_list.append(lbl)
Button(root, text=f'Destroy {i}',
command=lambda index=i: destroy_widget(index)).grid(row=i, column=1, sticky='nsew')
# option using partial (place import at the top)
# from functools import partial
# Button(root, text=f'Destroy {i}',
# command=lambda: partial(destroy_widget, i).grid(row=i, column=1, sticky='nsew')
# option defining function here (if so then the one at the top isn't needed)
# def destroy_widget(index=i):
# label_list[index].destroy()
# Button(root, text=f'Destroy {i}',
# command=destroy_widget).grid(row=i, column=1, sticky='nsew')
root.mainloop()
As I said, put the widgets in a list, then save index (probably better use a dictionary and save the key so that they can be deleted altogether with their instance, otherwise you can't delete them from the list because that should change other indexes which is gonna mess things up) to the function you are passing to the button so that they "remember" it, I provided 3 different (slightly) ways to do this, one is using anonymous functions, one is using partial, one is using normal functions

How to disable and destroy multiple buttons in tkinter?

There are 2 issues I'm facing at the moment.
When I click "Mike" button and and all Mike's sub buttons, I want the previous row buttons to be disabled but not button "Sara"
When I click "Sara" button I want Mike's sub buttons to be destroyed and returned to original state.
Having a hard time wrapping my head around the functionality. I feel like I'm taking a long route. Any help would be appreciated!
import tkinter as tk
app = tk.Tk()
app.geometry("300x300")
def buttonA1State():
if (buttonA1['state'] == tk.NORMAL):
buttonA1['state'] = tk.DISABLED
else:
buttonA1['state'] = tk.NORMAL
def btn3():
buttonA2 = tk.Button(app, text="Button A2",command = lambda:[buttonA1State(), btn5()])
buttonA2.grid(padx=10, pady=10, row=2, column=1)
buttonA3 = tk.Button(app, text="Button A3",command=btn4)
buttonA3.grid(padx=10, pady=10, row=2, column=2)
def btn4():
buttonA4 = tk.Button(app, text="Button A4")
buttonA4.grid(padx=10, pady=10, row=3, column=2)
def btn5():
buttonA5 = tk.Button(app, text="Button A5")
buttonA5.grid(padx=10, pady=10, row=3, column=1)
buttonA1 = tk.Button(app, text="Mike", command = lambda:[buttonA1State(), btn3()])
buttonA1.grid(padx=10, pady=10, row=1, column=1)
buttonB1 = tk.Button(app, text="Sara", command = btn3 )
buttonB1.grid(padx=10, pady=10, row=1, column=2)
app.mainloop()
You say you want to disable to the previous row, but you have no way to identify which buttons are in a row. You need to find a logical way to process your buttons preferably avoiding hard coding every button as you are when the actions have similarities. Creating an array of buttons might work where the list number is associated with grid position.
names = [["Mike", "Sara"]]
buttons = []
for x in range(names):
buttons.append()
for y in range(names[x]):
buttons[x].append(Button(app, text=names[x][y])))
The above code would allow you to refer to your buttons using easy to understand matrices you would have to adjust slightly since you start your buttons on row 1 but that is easily done. You would need a global value to keep up with which row and column is active.
You should create all possible buttons first then you use the grid() and grid_forget() methods to change which buttons are showing. You may need to organize your buttons in list (related to Mike or Sara) to help process them. If you want your program to scale easily and the buttons for Mike and Sara are similar buttons then you may want to create a class.
class APerson:
def __init__(self, window, name):
self.name = name
self.selected = False
self.select_button = Button(window, text=self.name command=select)
self.secondary_button = Button(window, text="Secondary")
self.another_button = Button(window, text="More Buttons")
def toggle_select(self):
self.selected = not self.selected
mike = APerson(app, "Mike")
sara = APerson(app, "Sara")
def main_callback:
if mike.selected:
etc...
app.after(1000, main_callback)
These are abstracts that you may find helpful. There are a lot of ways to do things in python and in programming in general so you really have to go with what makes the most sense for the problem you are trying to solve. You may prefer to create row objects that you pass buttons to instead of people objects that have buttons. I would avoid hard coding every action especially if you need your program to scale at all though.

how do i send a int value typed in a text-entry box to a mathematical expression?

my name is VĂ­tor. I'm totally new in programming, it is my second or third day in self learling python. I'm trying to build a metabolical rate calculator, it is the first thing that i could iamgine to do, i know about nothing from python. Then, i did it, but only stay in text editor (im using vs code), if i change the value in code, and run, i get the right value in terminal. But im tryint to operate it by a GUI, and i dont know how i type a numeric value in a text box, and this value are changed in my writed recipe. Ill show all my code from now, sorry for the weird words and long code, i'm really new in programming world, im from B. Anyway, thanks for reading.
import tkinter as tk
from tkinter import *
#FUNCAO DO BOTAO
def click1():
typed_text1=textentry1.get()
def click2():
typed_text2=textentry2.get()
def click3():
typed_text3=textentry3.get()
####MAIN
#TOP LEVEL CONTAINER
window = Tk()
window.title("Calculadora TMB")
#CONTAINER DE FUNDO
canvas = tk.Canvas(window, height=400,width=400, bg="green") .grid()
#CONTAINER QUADRO
frame1 = tk.Frame(canvas, height=200,width=200, bg="blue") .grid(row=0, column=1)
#IMAGEM
#LABEL
Label (frame1, text="CALCULADORA TMB", fg="red") .grid(row=0, column=0)
#CAIXA DE ENTRADA DE TEXTO
textentry1=Entry(frame1) .grid(row=1, column=1)
textentry2=Entry(frame1) .grid(row=2, column=1)
textentry3=Entry(frame1) .grid(row=3, column=1)
#SEND INPUT BUTTON
okbutton=tk.Button(frame1,text='Send', command=lambda:[click1(),click2(),click3()]) .grid(row=4, column=0)
#CANCEL BUTTON
cancelbutton=tk.Button(frame1,text='Cancel') .grid(row=5, column=0)
#OUTPUT TEXT
output= Text(frame1) .grid(row=6, column=0, padx=0.8, pady=0.8, columnspan=2)
#VARIABLES
Massa_corporal=66
Estatura=167
Idade=66
#RECIPES
Formula_HB_Homem=66.473+(13.752*Massa_corporal)+(5.003*Estatura)-(6.755*Idade)
Formula_HB_Mulher=655.1+(9.563*Massa_corporal)+(1.850*Estatura)-(4.676*Idade)
Formula_Williams1_H=(60.9*Massa_corporal)-54
Formula_Williams2_H=(22.7*Massa_corporal)+495
Formula_Williams3_H=(17.5*Massa_corporal)+651
Formula_Williams4_H=(15.3*Massa_corporal)+679
Formula_Williams5_H=(11.6*Massa_corporal)+879
Formula_Williams6_H=(13.5*Massa_corporal)+487
Formula_Williams1_M=(61*Massa_corporal)-51
Formula_Williams2_M=(22.5*Massa_corporal)+499
Formula_Williams3_M=(12.2*Massa_corporal)+746
Formula_Williams4_M=(14.7*Massa_corporal)+496
Formula_Williams5_M=(8.7*Massa_corporal)+829
Formula_Williams6_M=(10.5*Massa_corporal)+596
Formula_KTG=(((((1.255*Estatura)+(0.928*Massa_corporal)-64.8)*60)/1000)*24)*5
if Idade>=60:
print ((Formula_HB_Homem+Formula_Williams6_H+Formula_KTG)/3)
elif Idade>=30:
print((Formula_HB_Homem+Formula_Williams5_H+Formula_KTG)/3)
elif Idade>=18:
print((Formula_HB_Homem+Formula_Williams4_H+Formula_KTG)/3)
elif Idade>=10:
print((Formula_HB_Homem+Formula_Williams3_H+Formula_KTG)/3)
elif Idade>=3:
print((Formula_HB_Homem+Formula_Williams2_H+Formula_KTG)/3)
elif Idade>=0:
print((Formula_HB_Homem+Formula_Williams2_H+Formula_KTG)/3)
window.mainloop()```
To receive the value from a widget, you would want to use the get() function. The get() function will return whatever is in the text-box. See this page for more from the documentation.
You should also see the example on here

Tkinter button not returning value from function

I am currently trying to create a small UI for a function that returns some value from a data frame based on the string that has been entered. The string is split and each individual substring is looked up in my data frame using iloc. The issue is, when calling this function using a button in Tkinter, nothing is being returned. It works fine without Tkinter so I am unsure where the error is occurring.
master = Tk()
e1 = Entry(master)
list_of_inputs = e1.get().split()
def show_entry_fields():
i=0
while (i<len(list_of_inputs)):
return (backend.loc[backend['Keyword'] == list_of_inputs[i]])
i=i+1
Label(master, text="Enter Title").grid(row=0)
e1.grid(row=0, column=1)
Button(master, text='Show', command=show_entry_fields).grid(row=0, column=2, sticky=W, pady=4)
mainloop( )
Couple of things:
You are checking the value of your Entry before the user has a chance to fill it in. You should get the user input only when the button is pressed.
Your while loop in the show_entry_fields() function will always run once regardless of how many inputs provided, since you put a return statement inside the loop
Your handler function has to modify an existing data structure or graphical component, if you return your result you cant collect it
Possible implementation:
master = Tk()
e1 = Entry(master)
def show_entry_fields():
list_of_inputs = e1.get().split()
result = []
for entry in list_of_inputs:
result.append(backend.loc[backend['Keyword']] == entry)
# Alternatively, you can create the list with
# result = [backend.loc[backend['Keyword']] == entry for entry in list_of_inputs]
# Here, deal with the result
Label(master, text="Enter Title").grid(row=0)
e1.grid(row=0, column=1)
Button(master, text='Show', command=show_entry_fields).grid(row=0, column=2, sticky=W, pady=4)
mainloop()

Python Tkinter changing label text

I know that there are a lot of questions dealing with tkinter but I have looked at a bunch of them and none of them seem to help me.
import tkinter
class Calculator:
def __init__(self):
window = tkinter.Tk()
window.geometry("200x300")
window.title("Calculator")
lbl = tkinter.Label(window, text="placeholder", bg="blue", textvariable="labelText")
lbl.grid(row=0, column=0, columnspan=3)
self.firstNumArray = []
self.secondNumArray = []
self.operation = ""
self.currentNum = "first"
def appendNumber(self, number):
print("Appending Number")
if self.currentNum == "first":
self.firstNumArray.append(number)
print("".join(str(x) for x in self.firstNumArray))
lbl.config(text="".join(str(x) for x in self.firstNumArray))
window.update()
else:
self.secondNumArray.append(number)
for i in range(1,4):
string = "Creating button at ({0},{1})".format(0,i)
print(string)
button = tkinter.Button(text=i, command=lambda: appendNumber(self, i))
button.grid(row=1, column=i-1)
for i in range(1,4):
string = "Creating button at ({0},{1})".format(1,i)
print(string)
button = tkinter.Button(text=i+3, command=lambda: appendNumber(self, i+3))
button.grid(row=2, column=i-1)
for i in range(1,4):
string = "Creating button at ({0},{1})".format(2,i)
print(string)
button = tkinter.Button(text=i+6, command=lambda: appendNumber(self, i+6))
button.grid(row=3, column=i-1)
div = tkinter.Button(text="/")
mult = tkinter.Button(text="*")
add = tkinter.Button(text="+")
sub = tkinter.Button(text="-")
add.grid(row=1, column=3)
sub.grid(row=2, column=3)
mult.grid(row=3, column=3)
div.grid(row=4, column=3)
button = tkinter.Button(text="0")
button.grid(row=4, column=1)
window.mainloop()
calc = Calculator()
When I launch the program the window opens. When I click on a button the text in the label does not change. I have tried using a StringVar as the textvariable and then calling the set() function, but that did not work either. I think it has to do with the scope of the function. I had to place the appendNumber() function inside the __init__() because for some reason self.lbl = tkinter.Label() makes nothing pop up at all.
There are a few problems with your code.
labelText should, of course, be a StringVar and not a string...
labelText = tkinter.StringVar()
lbl = tkinter.Label(window, bg="blue", textvariable=labelText)
lbl.grid(row=0, column=0, columnspan=3)
Now you can use labelText.set to update the text. Also, no need for self parameter or window.update
def appendNumber(number):
if self.currentNum == "first":
self.firstNumArray.append(number)
labelText.set("".join(str(x) for x in self.firstNumArray))
else:
self.secondNumArray.append(number)
You can put all the buttons in one loop using // (integer (!) division) and % (modulo) operations. Also, be aware that the variable in the lambda is evaluated when the function is called, not when it is declared, i.e. all the lambdas will use the last value of i (9 in this case) -- see e.g. here. As a remedy, use lambda n=i+1: appendNumber(n).
for i in range(9):
btn = tkinter.Button(text=i+1, command=lambda n=i+1: appendNumber(n))
btn.grid(row=i//3+1, column=i%3)
Not really a problem, but since you don't need a reference to those buttons, you can make your code a bit more compact (same for the others):
tkinter.Button(text="/").grid(row=1, column=3)

Categories

Resources