Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Button action in a class
-
I have a ui.button created in a class function. The button action is pointing to a different function in the same class.
The action will not call when the button is pushed. Should this work? ( This is simplified logic of the actual code)
class Note: def f1(self): print 'hello' def f2(self): b = ui.button() b. action = f1 c = Note() c.f2()
-
In the line
b.action = f1
you're trying to set the globalf1
as theaction
ofb
- however there is no such global. To use the methodf1
ofself
(an instance ofNote
) as theaction
, you need to explicitly refer to it asself.f1
. (Unlike e. g. in Java, wheref1
inside a class translates tothis.f1
.)action
functions also need to take a single parameter,sender
, which is the UI object that calls the function.f1
currently doesn't have that, meaning that you'll get an exception when theButton
tries to run itsaction
. -
Unfortunately, an exception is NOT thrown but instead the action just fails to get called silently :-(
A minimal working version:
import ui class Note(ui.View): def f1(self, sender): # adding the sender is key print('hello ' + sender.title) def f2(self): b = ui.Button(title='OK') b.action = self.f1 self.add_subview(b) c = Note() c.present() c.f2()
-
Yes, the silent exception is what confused me. I think all your help explained it well. Thank you.
What if with the example above I wanted to call f1 independently (which now contains the sender argument)? When I try the code below it has an error:
c.f1() #this cause argument error
c.f1(0) # this works but why?
-
c.f1(0)
does NOT work but instead it throws an AttributeError because an int does not have a .title attribute.My recommendation would be that you write:
def f1(self, sender=None): # added a default value for sender if sender: print('hello ' + sender.title) # called as an action else: print('hello, world!') # called as a method # [ ... ] c.f1() # called as a method with no "sender" parameter
-
Excellent, good info. Thank you.
-
When using
None
as a default value, it's best to check forNone
itself (if arg is None
), instead of relying on its falseyness (if not arg
). In this case it's unlikely thatsender
will ever be something that is falsey, but in other cases this can be problematic. For example0
is falsey, and when writing a function that deals with numbers you don't want0
to be considered as "no argument given".