Tkinter command for button not working [duplicate] - python

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 5 years ago.
I'm trying to make my program change the text based on a variable selected in the dropdown menu, but the button to activate the command doesn't seem to be working. From what I can see, the select function run's once the program is loaded and then never again, regardless of when I click the button.
from Tkinter import *
class App:
def __init__(self, root):
self.title = Label(root, text="Choose a food: ",
justify = LEFT, padx = 20).pack()
self.label = Label(root, text = "Please select a food.")
self.label.pack()
self.var = StringVar()
self.var.set("Apple")
food = ["Apple", "Banana", "Pear"]
option = apply(OptionMenu, (root, self.var) + tuple(food))
option.pack()
button = Button(root, text = "Choose", command=self.select())
button.pack()
def select(self):
selection = "You selected the food: " + self.var.get()
print(self.var.get()) #debug message
self.label.config(text = selection)
if __name__ == '__main__':
root = Tk()
app = App(root)
root.mainloop()
I'm a beginner on Tkinter, and I'm trying to figure out the basics before I go into making my full app. Thanks in advance :)

Try changing button = Button(root, text = "Choose", command=self.select()) to button = Button(root, text = "Choose", command=self.select). Note the removed parentheses after self.select. This way, the method only gets referenced and not actually executed until you press the button.

Your main issue is you don't need the parentheses when setting command=self.food():
button = Button(root, text="Choose", command=self.select)
As a side-note, the way you generate your OptionMenu is slightly unusual. You can use the following instead, which is more consistent with the rest of your code:
option = OptionMenu(root, self.var, *food)

The command parameter documentation as per tkinterbook.
(A function or method that is called when the button is pressed. The callback can be a function, bound method, or any other callable Python object. If this option is not used, nothing will happen when the user presses the button.)
*****************************modified code*******************************
from Tkinter import *
class App:
def __init__(self, root):
self.title = Label(root, text="Choose a food: ",
justify = LEFT, padx = 20).pack()
self.label = Label(root, text = "Please select a food.")
self.label.pack()
self.var = StringVar()
self.var.set("Apple")
food = ["Apple", "Banana", "Pear"]
option = apply(OptionMenu, (root, self.var) + tuple(food))
option.pack()
button = Button(root, text = "Choose", command=self.select)
#use function name instead of aclling the function
button.pack()
def select(self):
selection = "You selected the food: " + self.var.get()
print(selection) #debug message
self.label.config(text = selection)
if __name__ == '__main__':
root = Tk()
app = App(root)
root.mainloop()

Related

Why isn't the grid_forget method working?

Trying to make an tkinter atm gui, in the gui I made it so you can create new accounts with a set balance. I also wanted to make it so you can delete the last previous account you created but ran into an error. I stored all created accounts in a list and to delete them I tried to use the grid_forget method to delete the account in the -1 index but the program says it doesn't have an attribute called grid_forget, please help and thank you.
code:
import tkinter as tk
from tkinter import messagebox as mb
class BankAccount(tk.Tk):
def __init__(self, frame_title):
super().__init__()
self.title(frame_title)
self.geometry("350x370")
self.acc_list = []
#main window buttons
self.addAcc_button = tk.Button(self, text="Add Account", width=50, height=3, command=self.addAcc_window)
self.addAcc_button.grid()
self.removeAcc_button = tk.Button(self, text="Clear accounts", width=50, height=3, command=self.removeAcc)
self.removeAcc_button.grid()
self.deposit_button = tk.Button(self, text="Deposit", width=50, height=3)
self.deposit_button.grid()
self.withdrawal_button = tk.Button(self, text="Withdraw", width=50, height=3)
self.withdrawal_button.grid()
#main window label
self.accounts_label = tk.Label(self, text="Accounts: ", justify="center")
self.accounts_label.grid(pady=10)
#create second window when add acc* button is pressed + done button function/command
def addAcc_window(self):
self.AAW = tk.Toplevel(self)
self.accName_label = tk.Label(self.AAW, text="Enter Account Name:")
self.accName_label.grid()
self.accName_entry = tk.Entry(self.AAW)
self.accName_entry.grid()
self.AAW_done_button = tk.Button(self.AAW, text="Done", command=self.AAW_Done_button)
self.AAW_done_button.grid(pady=20)
def AAW_Done_button(self):
if len(self.accName_entry.get()) == 0:
mb.showerror("Blank entry", "Field cannot be blank")
else:
self.add_accLabel = tk.Label(self, text="Account " + self.accName_entry.get() + ": Balance($0)")
self.add_accLabel.grid()
self.acc_list.append(self.accName_entry.get())
self.AAW.destroy()
#create third window when remove acc* button is pressed
def removeAcc(self):
self.acc_list[-1].grid_forget()
root = BankAccount("ATM")
root.mainloop()
In your code, self.acc_list contains the name of the accounts, so they are all strings which does not have grid_forget() function.
For your case, you need to add two things into self.acc_list for each account:
the account name
the label showing account name and balance
def AAW_Done_button(self):
...
self.acc_list.append([self.accName_entry.get(), self.add_accLabel])
...
Then you can delete the last account inside removeAcc() as below:
def removeAcc(self):
if self.acc_list:
name, label = self.acc_list.pop()
label.grid_forget() # or better call label.destroy()

Python Tkinter label not destroying

So I'm attempting to make a program with tkinter, and so far, things have gone somewhat as hoped, and I nearly achieved what I wanted.
But I've got a problem with destroying labels.
from tkinter import *
root = Tk()
root.geometry("500x500")
def controleerAntwoord(gekozenHeld, submit, eersteHintButton):
antwoord = entry.get()
if antwoord == gekozenHeld:
submit.destroy()
eersteHintButton.destroy()
eersteHint("destroy", button)
startspel()
def eersteHint(superheldHint, button):
hintTextLabel = Label(root, text = "First hint: ")
hintLabel = Label(root, text = superheldHint)
if superheldHint != "destroy":
hintTextLabel.pack()
hintLabel.pack()
button.destroy()
if superheldHint == "destroy":
hintTextLabel.destroy()
hintLabel.destroy()
def startspel():
entry.delete(0, 'end')
gekozenHeld = "test"
superheldHint1 = 'hey'
eersteHintButton = Button(root, text = "Give First Hint", command = lambda: eersteHint(superheldHint1, eersteHintButton))
submit = Button(root, text = "Submit Answer",foreground = "blue", command = lambda: controleerAntwoord(gekozenHeld, submit, eersteHintButton))
eersteHintButton.pack(side = BOTTOM)
entry.pack(side = BOTTOM)
submit.pack(side = BOTTOM, pady = 20)
def start_up():
name = entry.get().strip()
if name != "":
button.destroy()
giveName.destroy()
startspel()
giveName = Label(root, text="Insert your name: ")
entry = Entry(root)
button = Button(root, text="Enter", command=start_up)
entry.pack()
button.pack()
root.mainloop()
This is my current code so far, I know it looks big, but a lot of it can be ignored for this question.
As to how the program works, you enter your name and get taken to the next window.
There you can press the submit button and enter some text, as well as asking for a hint.
When you press the hint button, you get some text on the screen, and when you submit the correct answer, which in this case, is "test", the text should disappear. But it does not.
Any ideas on what I'm doing wrong?
The problem is that you're using a local variable, but expecting that local variable to somehow be remembered the second time you call the function. All your code does is create a label and then immediately destroy the one it just created. If you want it to destroy the one created earlier, you'll have to store that in a global variable.

How can I get the value of 'username' inside the function Login() to use it on another python program?

from Tkinter import *
root = Tk()
root.geometry("230x100")
L1 = Label(root, text="Login page", bg = "blue", fg = "white")
L1.pack(fill = X, ipadx = 5, ipady = 5)
V = StringVar(root, value='Enter username here')
E1 = Entry(root, textvariable=V)
E1.pack(side = LEFT, padx = 5, pady = 5)
def Login():
username = V.get()
print "Username is '" + username + "'"
B1 = Button(root, text ="Login" , command = Login)
B1.pack(side = RIGHT, fill = X, pady=5)
mainloop()
I have been trying to get the value of 'username' in the function Login() to use it on another python program.
I have tried setting it as global variable and changing its scope but I am not getting anything.
I need to use the value of 'Username' outside the function Login(). Please provide your insights.
Think about scope for a moment. When your program ends, all memory (meaning variables, objects, etc.) are released. The only 2 ways I can think of to pass something from one program to another is:
1) Write the username value to a file which the next program can read as part of its startup.
2) Have a third "controller" or "launcher" program that runs the program above, takes a return value from that program, then passes that value as a parameter to the next program.
But in any case, you will have to save that value past the scope of the program above.
1) Create a python file say 'global_vars.py' and add this line in it.
#global_vars.py
global_V = ''
2) Import this global_vars.py wherever you want set the variable as below:
#main.py
from Tkinter import *
import global_vars
root = Tk()
root.geometry("230x100")
L1 = Label(root, text="Login page", bg = "blue", fg = "white")
L1.pack(fill = X, ipadx = 5, ipady = 5)
V = StringVar(root, value='Enter username here')
#Set the global variable
global_vars.global_V = V
E1 = Entry(root, textvariable=V)
E1.pack(side = LEFT, padx = 5, pady = 5)
3) Consider you want to use this value in python program present in file "test.py". Just import global_vars.py and use this variable
#test.py
import global_vars.py
def printUserName():
print "Username is -", global_vars.global_V
If you have to python files, one called main.py that contains your main program (I assumed it was a GUI program) and the login.py file that contains the login program.
main.py
from tkinter import Tk, Label
from login import LoginGUI
class mainGUI(Tk):
def __init__(self):
Tk.__init__(self)
Label(self, text="You need to login first",
bg="blue", fg="white").pack(fill="x", ipadx=5, ipady=5)
# open login dialog
login = LoginGUI(self)
# wait for the user to log in
self.wait_window(login)
username = login.getLogin()
Label(self,
text="Your username is " + username).pack(fill="x", ipadx=5, ipady=5)
self.mainloop()
if __name__ == '__main__':
mainGUI()
login.py
from tkinter import Toplevel, StringVar, Entry, Button, Label
from tkinter import Toplevel, StringVar, Entry, Button, Label
class LoginGUI(Toplevel):
def __init__(self, master):
Toplevel.__init__(self, master)
self.transient(master)
self.geometry("230x100")
Label(self, text="Login page",
bg="blue", fg="white").pack(fill="x", ipadx=5, ipady=5)
self.username = ""
self.usernameVar = StringVar(self, value='Enter username here')
E1 = Entry(self,
textvariable=self.usernameVar)
E1.pack(side="left", padx=5, pady=5)
Button(self, text="Login",
command=self.Login).pack(side="right", fill="x", pady=5)
E1.focus_set()
def Login(self):
self.username = self.usernameVar.get()
self.destroy()
def getLogin(self):
return self.username
If your main program have no GUI, replace Toplevel by Tk in login.py and add a self.mainloop at the end of the __init__ method.
You can launch the other program using subprocess, or refactor the other program so the username can be passed as the parameter of a function, and import that program as module of your main program.

Tkinter check button not working when in another window [duplicate]

This question already has an answer here:
How do I create child windows with Python tkinter?
(1 answer)
Closed 6 years ago.
When you run this code and try and check the the check button and click the button to print out the value of the check button it does not work. I can't figure out why. It prints out 0 whether checked or unchecked.
from tkinter import *
def awesome():
def click_me():
print(var.get())
return
root = Tk()
root.title("a good try")
var = IntVar()
x = Checkbutton(root, text = "check me", variable = var)
y = Button(root, text = "click me", command = click_me)
x.pack()
y.pack()
root.mainloop()
return
def main():
main = Tk()
cool = Button(main, text = "click", command = awesome)
cool.pack()
main.mainloop()
main()
change root = Tk() to root = Toplevel()
need to use Toplevel() for a window that opens on another window.

Get the same input multiple times in python tkinter?

I am making a program to get multiple user names and store them in a XML file. The XML part works fine, but I am having trouble with the GUI. I want to be able to ask the user how many users he wants to input, then repeat an Entry that number of times. How can I do that, while maintaining a quit function? I tried:
def quitter():
exit()
quit()
quitterButton = Button(master, text="Quit", command=quitter)
mainCanvas.create_window(50, 330, window=quitterButton, tag="quitter")
num = int(raw_input("How many users are you going to put in?"))
for x in range(0,num):
#Create User entry Variable
userEnter = StringVar()
usrVar = ""
#Create enter box:
userEntryBox = Entry(master, textvariable = userEnter)
mainCanvas.create_window(250, 300, window=userEntryBox, tag="UserEnterA")
def gotInput(self):
usrVar = userEnter.get();
mainCanvas.create_text(250, 330, text="User Inputted: " + usrVar, tags="0")
mainCanvas.delete("UserEnterA")
#Bind entry box
userEntryBox.bind('<Key-Return>', gotInput)
userEntryBox.wait_window(userEntryBox)
#Create a new user element
newUsr= ET.Element('Member')
#Add element to the Root
root.append(newUsr)
#Make a sub element Name, set name
usrName = ET.SubElement(newUsr, 'Name')
usrName.text = usrVar;
...
tree.write('./output.xml')
What is the best way to go around it? I won't know the number of inputs, and I want the quit button to work at all times .
Behavior of your program is a bit unclear for me, but I try to help.
First solution: show tkinter askstring dialog num times. You can break for loop if user press Cancel button. It's not exactly what you want, but it's very easy to implement:
from tkinter import *
import tkinter.simpledialog as simpledialog
def add_users():
n = simpledialog.askinteger('', 'How many users are you going to put in?', initialvalue=1, minvalue=1, maxvalue=10)
if not n: # 'Cancel'
return
for i in range(n):
user = simpledialog.askstring('', 'User #%s from #%s' % (i+1, n))
if user is None: # 'Cancel'
return
# Do something useful
print(user)
root = Tk()
Button(root, text='Add users', command=add_users).pack(padx=50, pady=50)
Button(root, text='Quit', command=root.destroy).pack(pady=30)
root.mainloop()
Second (if you want to put entry and all new names to window with quit button):
from tkinter import *
import tkinter.simpledialog as simpledialog
class YourApp():
def __init__(self):
self.root = Tk()
Button(self.root, text='Quit', command=self.root.destroy).pack(pady=20)
self.ask_button = Button(self.root, text='Add users', command=self.add_users)
self.ask_button.pack(padx=50, pady=50)
self.root.mainloop()
def add_users(self):
self.users_count = 0
self.user_name = StringVar()
self.frame = Frame(self.root)
self.frame.pack()
self.users_count = simpledialog.askinteger('', 'How many users are you going to put in?', initialvalue=1, minvalue=1, maxvalue=10)
self.user_entry = Entry(self.frame, textvariable=self.user_name)
self.user_entry.pack(pady=10)
self.user_entry.bind('<Key-Return>', self.on_new_user)
self.user_entry.focus_set()
def on_new_user(self, event):
# your code
print(self.user_name.get())
Label(self.frame, text='User Inputted: %s' % self.user_name.get()).pack()
self.users_count -= 1
if not self.users_count:
self.user_entry.destroy()
self.user_name.set('')
YourApp()
There are three geometry managers in Tkinter: place (it's very similar to canvas in your case), grid and pack.
Canvas usually used for drawing pictures or graphs.

Categories

Resources