How to set action attribute in UI editor to a class-method handler rather than a function?
How do I set the action attribute in the UI designer to a object handler method rather than a function? I see how to set the action attribute of a view such as Button to a function such as 'button_tapped' in code outside of the UI Designer, but I want to both use the UI editor AND code in a object oriented fashion. I therefore want to associate my handler METHOD to the action attribute. In code it is simple - you create an instance of your handler class that contains the handler method and then you bind the Button view's action attribute to that instance.method.
But is is possible to set this in the UI editor, which nicely separates interface from implementation, given that in code its the actual instance name you are setting as in myButton.action = anInstancePreviouslyJustCreated.method? I tried playing with creating the instance of the handler class at different points in the code but no matter what I try I can not get the handler method to be called. What would the value in the UI editor be exactly for the action attribute?
Not sure if and how methods can be set as actions from the UI editor, but you could set the method in code after loading the view:
import ui class ActionClass(object): def action_method(self, sender): sender.title = "I got tapped!" handler = ActionClass() root = ui.load_view() root["button1"].action = handler.action_method root.present()
It's just one line of code and to me doesn't look as bad as you seem to describe it ;) Have you tried storing the method in a global name before loading the view? That might work, but would not be very clean code...
Thanks. It's not as nice and abstract as it would be tucked away in the pyui file but it is at least a workaround if the goal is to use the ui editor for all ui construction and an OO-style of coding in the implementation script. I agree with you that it is likely not possible since you need a live instance of the implementation when you make the association.
The only way you can do this at the moment is to have the object that defines the action methods also load the view, e.g. in the initializer. In the following example, the action in your pyui file would be set as
import ui class MyViewController (object): def __init__(self): self.view = ui.load_view() def action_method(self, sender): sender.title = 'tapped' vc = MyViewController() vc.view.present()
I think that, given I prefer to use OO and classes/objects to implement the code behind the widgets, this is not actually a limitation but a role that makes sense anyway for this object.
@omz, when you say that "The only way you can do this at the moment..." are you saying that this is a restriction? Like I say, the way I see it, it makes sense as the preferred way to load the view anyway.
when you say that "The only way you can do this at the moment..." are you saying that this is a restriction? Like I say, the way I see it, it makes sense as the preferred way to load the view anyway.
It definitely makes sense to load the view this way, and that's why it's one of the two supported methods of assigning actions.
To be honest though, if I'd write the
load_viewfunction again today, I would probably add an explicit 'owner' parameter, as that would be more pythonic in my opinion.
When you think about how you might write a
load_viewfunction in pure Python, it becomes clear that it has to do quite a bit of "magic" you might not expect. Normally, when you call a function from a method, that function has no idea what
selfrefers to, because it's just a local variable (parameter) in the scope of your method.
load_viewfunction basically has to look at the stack to determine what
selfrefers to in the context of your call. This is of course possible to do in Python, but it's a little ugly and goes against the "explicit is better than implicit" principle.