Button command being called automatically - python

For some reason, this Button is automatically calling bot_analysis_frame without the button being pressed. I'm guessing it's because the command is a function with arguments.
Is there a way to have the button only call this function and pass the required variables only upon being pressed?
Button(topAnalysisFrame, text='OK', command=bot_analysis_frame(eventConditionL, eventBreakL)).pack(side=LEFT)

Read the section here on passing callbacks.
You are storing the result of that function to the command argument and not the function itself.
I believe this:
command = lambda: bot_analysis_frame(eventConditionL,eventBreakL)
might work for you.

I'm pretty sure this has been answered before. Instead of this:
Button(topAnalysisFrame,
text='OK',
command=bot_analysis_frame(eventConditionL,eventBreakL)).pack(side=LEFT)
You could use lambda like so:
Button(topAnalysisFrame,
text="OK",
command=lambda: bot_analysis_frame(eventConditionL, eventBreakL)).pack(side=LEFT)

Related

Label appearing conditionally

I am trying to make a label appear if the condition of my entry (textbox) is met. Unfortunately I cannot see anything when I am pressing the button on the testing. Here is what I have:
from tkinter import *
main= Tk()
firstname=Entry(main).place(x=30, y=50)
def register():
if any(i.isdigit() for i in firstname.get())== True:
print (Label(main,text='no numbers please').place(x=30, y=180))
else:
print(Label(main, text='pass').place(x=40, y=170))
register=Button(main,text='REGISTER', command= lambda :register).place(x=300, y=200)
There are at least three problems with your code. The first is in how you define the button's command:
register=Button(main,text='REGISTER', command= lambda :register)
When you do command=lambda: register, you're telling the button "when you're clicked run the code register". register all by itself does nothing. Since register is (supposed to be) a function, you need to call it like register() inside the lambda.
Since you aren't passing any values to the function, the lambda is completely unnecessary. Instead, just directly reference the function: command=register without the parenthesis.
The second problem is that you've used the name register to be two different things: a function and a reference to a widget. Because of the ordering of the code, command=register or command=lambda: register() will try to call the button rather than the function.
The third problem is a very, very common mistake. In python, when you do x = y().z(), x is given the value of z(). Thus, register = Button(...).pack(...) returns the value of pack(...) and pack (and grid and place) always returns None.
Therefore, you've set register to None, and when you try to call it you get NoneType object is not callable.
In addition to fixing the command, you need to pick a different name for either the function or the button. And you should not be calling place (or pack or grid) in-line with creating the widget. They should be separate steps.
So, putting that all together, you need to define firstname like this so that firstname is not None:
firstname=Entry(main)
firstname.place(x=30, y=50)
And then you need to define the button like this:
register_button = Button(main,text='REGISTER', command= register)
register_button.place(x=300, y=200)

Python: button command isn't running?

For an A-level computing project, I am making a car data monitoring system. I have a button that opens the filedialog.askopenfilename method. When I pass this through a method like below, it doesn't work. However when I pass it straight into the button, it works fine. Any ideas as to why?
Doesn't work:
def get_data_file():
filedialog.askopenfilename
return
OpenfileButton=Button(master,text="Select File",width=20,command=get_data_file).grid(row=3, column=2)
works:
OpenfileButton=Button(master,text="Select File",width=20,command=filedialog.askopenfilename).grid(row=3, column=2)
You need to actually call the function
def get_data_file():
filedialog.askopenfilename()
When you pass the function to the button you should not call it but simply pass it to be called when the button is clicked, but as you have now wrapped it in another function it must be called by you.
The return is redundant and can be left out if you wish. All python functions return None by default.

Define pressed button of drop-down list in Tkinter Python

I created a drop-down list using Menubutton from Python Tkinter, but i can't detect which button was pressed ('button-1', 'button-2' or 'button-3')
from Tkinter import *
widget = Frame()
widget.pack()
btnMenu = Menubutton(widget, text='Select action')
contentMenu = Menu(btnMenu)
btnMenu.config(menu=contentMenu)
btnMenu.pack()
btnList = ['button-1', 'button-2', 'button-3']
for btn in btnList:
contentMenu.add_command(label=btn, command=???)
mainloop()
What should i use for "command=" in the string
contentMenu.add_command(label=btn, command=???)
in order to define particular button? Thank you!
What you're looking for is lambda. You can use lambda in your command call like such:
contentMenu.add_command(label=btn, command = lambda btn=btn: buttonClicked(btn))
Then make a method called buttonClicked which would take one argument which would reflect which button has been pressed. Here's a minimal example of what that would look like:
def buttonClicked(btn):
print btn
Ideally though if each button has an entirely different set of execution instructions then they should each get their own method and perhaps you change the list to a tuple of (name, method). This is usually the case for why you would use a menubutton instead of an optionmenu. If you're simply calling the same method for all of them then you might want to consider switching to an optionmenu instead.

Tkinter's mainloop() Calling Button Function Automatically

I'm pretty new to Tkinter but starting to try to put more complex GUI's in my scripts. So this must be pretty basic but I can't figure out what's going wrong.
What I want is pretty simple, a bunch of data entry options and at the bottom an exit and submit buttons. It seems though that mainloop() or something else keeps running the button's command without any user input. Thus because of the exit button, the applet is destroyed before it even shows up. If I put the buttons outside of the mainloop(), there is no problem, but of course it doesn't make sense and the buttons don't show up.
button_exit = Tkinter.Button(root, text = 'Exit', command = root.destroy())
button_exit.grid(row=3, column=0, pady=10, sticky='E')
button_query = Tkinter.Button(root, text = 'Query', command = intQuery())
button_query.grid(row=3, column=1, padx=10, sticky='E')
root.mainloop()
That's basically the problem area of the code. The rest is just that data entry fields, most of the script hasn't even been written yet.
Thanks in advance.
Change
command = root.destroy()
to
command = root.destroy
The reason is this: The parentheses call the method, and method arguments are evaluated before being passed to the method. This is why your program is exiting too early.
Without the parentheses, you are referencing the method as an object which can be passed to the Tkinter.Button, stored, and called later when the button is pressed.
Then do the same with command = intQuery().

Python ttk.Button -command, runs without button being pressed

I'm making a small script in python with ttk and I have a problem where a function runs where it shouldn't. The button code looks as follows:
btReload = ttk.Button(treeBottomUI, text="Reload", width=17, command=loadModelTree(treeModel))
btReload.pack(side="left")
and the function is as this:
def loadModelTree(tree):
print ("Loading models...")
allModels = os.listdir(confModPath)
for chunk in allModels:
...
For some reason, the function runs without the button being pressed. Why?
Markus, yes, that's the right solution, but it is not because you can't use multi-argument commands in widget callouts. Consider, in your original code, ...command=loadModelTree(treeModel)... is an invocation of the method. Lambda allows you to abstract the command so you can have an arbitrary number of arguments without confusing the interpreter by invoking it, e.g., ...command=lambda arg1=myarg1, arg2=myarg2, arg3=myarg3: myCallout(arg1, arg2, arg3)....
I hope that makes what is going on a bit clearer.
Well, as I found the answer, I'll answer my own question.
It appers that ttk.button commands does not support sending arguments to functions so the work around is to do as follows:
btReload = ttk.Button(treeBottomUI, text="Reload", width=17, command=lambda i=treeModel: loadModelTree(i))
btReload.pack(side="left")
Simple as pie!

Categories