Python: button command isn't running? - python

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.

Related

Moving TKinter Window.destroy to a function from a button, not so simple?

I'm giving myself a crash-course in Python and TKinter, but there is one small detail I can't grasp.
Closing a Toplevel window in a function instead of a button.
My button alone works perfect:
button = Button(UpdateWindow, text="Destroy Window", command=UpdateWindow.destroy)
Using a button with a reference to a close function bombs:
def Close():
tkMessageBox.showwarning('', 'Close function called', icon="warning")
command=UpdateWindow.destroy
btn_updatecon = Button(ContactForm, text="Update", width=20, command=lambda:[UpdateData(), Close()])
What am I missing in the function? It is being called, but no close.
The SQLite3 project im working with is here
Any guidance greatly appreciated.
command=UpdateWindow.destroy defines a variable. If you want to keep the command variable use command(), while if you want the recommended way use UpdateWindow.destroy()

in TKInter Why am I getting an error - takes 1 positional argument but 2 were given

Just learning Python and TKInter and have come across this error in my code. Don't know what I'm missing and hoping someone can help. I've included the button code and the function to show you what I have.
def change_font(self):
self.label_name['font'] = "Sawasdee"
self.button1 = Button(self.myframe2, text="Change font")
self.button1.bind("<Button-1>", self.change_font)
When you bind a function to an event, tkinter will call that function with an argument which represents the event which triggered the function to be called. That is why the error says it expected one argument (self) but got two (self, event).
You need to account for that event parameter even if you don't need it. The easiest way is to make it an optional named parameter:
def change_font(self, event=None):
self.label_name["font"] = "Sawasdee"
It's usually incorrect to use bind on a button. The Button widget accepts an attribute named command which can be used to tie the button to a function. In this case, the function will not get the event parameter:
def change_font(self):
self.label_name["font"] = "Sawasdee"
self.button1 = Button(self.myframe2, text="ChangeFont", command=change_font)
The advantage to using command is that it automatically supports not just clicking with the mouse, but also interacting with the button using the keyboard.

Python TK Notebook tab change check

Newbie programmer here. I am building a tk based desktop app and ran into an issue:
I have a main window with several stuff in it including two tabs:
global nBook
nBook = ttk.Notebook(self, name="book")
nBook.place(x=300,y=400)
frameOne = ttk.Frame(nBook, width=100, height=100)
frameTwo = ttk.Frame(nBook, width=100, height=100)
nBook.add(frameOne, text='T1')
nBook.add(frameTwo, text='T2')
frameOne.bind("<<NotebookTabChanged>>", self.routine())
frameTwo.bind("<<NotebookTabChanged>>", self.routine())
routine() is a function that SHOULD perform a check every time T2 is selected
def routine(self):
if str(nBook.index(nBook.select())) == "2":
# Do stuff
else:
pass
Problem is that it doesn't do anything when the tab is changed except for calling the routine function as soon as I open the app and never again. I just can't figure out what I'm doing wrong.
Could anyone point out the mistake(s) I'm making?
EDIT: Same issue if I try
nBook.bind("<<NotebookTabChanged>>", self.xbRoutine())
The error comes from the event binding statements: when using self.routine() the callback is called when the bind statement is executed, not when the event is triggered. To get the correct behavior, the second argument of bind should be the name of a function not a call to this function, so simply remove the parentheses.
Another error: when using bind, the callback function is expected to have a first argument (traditionnaly called event) storing the event parameters. So you should define your callback as:
def routine(self, event):
...
I had the same problem. The answer given by #sciroccorics is not complete.
What you bind is not the tab itself, but the notebook.
So, it should be
nBook.bind("<<NotebookTabChanged>>", self.xbRoutine)
Alternatively you could use lambda.
In your case this will look something like this:
frameOne.bind("<<NotebookTabChanged>>", lambda _: self.routine())
Don't forget the _, otherwise you will get a TypeError, since the event is passed as an argument.
lamba is really helpful if your function requires one or more arguments.

Give/get arguments in popup from "on_press"

Pardon me for my simple question, but I don't understand some thing.
I want to give a few arguments from button which is located in popup window in one method to another method.
Example:
.py code
class GeneralForm(TabbedPanel):
def EDIT(self,D):
box1=BoxLayout(orientation='vertical')
t1=TextInput(text=GeneralForm.PARSE(self,D))
b2=Button(text='Save')
b3=Button(text='Cancel')
box2=BoxLayout()
box2.add_widget(b2)
box2.add_widget(b3)
box1.add_widget(t1)
box1.add_widget(box2)
popup = Popup(content=box1,auto_dismiss=False,size_hint=(.75,.75),title='Edit')
b2.bind(on_press=self.SAVE_EDIT) <====== There is a problem
b3.bind(on_press=popup.dismiss)
popup.open()
def SAVE_EDIT(self,instance):
!!! DOING SOMETHING !!!
https://s3.amazonaws.com/xasan/snapshot/stack1.png
What I want:
In method "EDIT" I have text input "t1". After changing text in this text input I press button "b2" which calls method SAVE_EDIT with two arguments.
So, I want to give the third agrument to "SAVE_EDIT" method which will return an edited text in t1.
Something like this:
.py code
class GeneralForm(TabbedPanel):
def EDIT(self,D):
box1=BoxLayout(orientation='vertical')
t1=TextInput(text=GeneralForm.PARSE(self,D))
b2=Button(text='Save')
b3=Button(text='Cancel')
box2=BoxLayout()
box2.add_widget(b2)
box2.add_widget(b3)
box1.add_widget(t1)
box1.add_widget(box2)
popup = Popup(content=box1,auto_dismiss=False,size_hint=(.75,.75),title='Edit')
b2.bind(on_press=self.SAVE_EDIT(t1.txt)) <====== There is a problem
b3.bind(on_press=popup.dismiss)
popup.open()
def SAVE_EDIT(self,instance,TEXT): <====== There is a problem
!!! DOING SOMETHING with TEXT!!!
Step-by-step:
Popen window was opened with some text in the text input.
We edited text, deleted something or added.
We are clicking on button "Save"(b2) and all text in txt input(t1) push to method "SAVE_EDIT" where we save,parse or do something else
with this text.
Thanks in advance.
You could use lambda:
on_press=lambda instance, text=t1.txt: self.SAVE_EDIT(instance, TEXT=text)
Or functools.partial():
on_press=partial(self.SAVE_EDIT, TEXT=t1.txt)
Both variants use t1.txt at the time of the bind call i.e., the value may be obsolete by the time you press the button.
To use the current most recent value:
on_press=lambda instance: self.SAVE_EDIT(instance, TEXT=t1.txt)
In this case, t1.txt is called each time the callback is invoked.

Button command being called automatically

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)

Categories