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.
Trying to isolate my code for different views
-
Again, sorry, If this is stupid. But trying to seperate my code for different views I am loading. I did the below code and it seems to work, but I am guessing I am going around it the hard way. Just trying to get each view to have its own code. I hope the code below makes sense, I am finding it very hard to put into words
import ui import my_customers def do_customers(sender): # one way (not what i want) v = ui.load_view('customers') v.present('sheet') def do_customers(sender): # 2nd way ''' my_customers.py has setup function, that just does v = ui.load_view('customers') v.present('sheet') but all the action/functions from the ui items are now local to this my_customers.py , which is what i wanted. ''' my_customers.setup() if __name__ == '__main__': v = ui.load_view('my_main_view') v.right_button_items = [ui.ButtonItem('Customers', None , do_customers)] v.present('sheet')
-
ui.load_view
reads all names ("variables") from the environment it is run in, so there is no "good" way to make it work with a different environment. One option is running it directly in the desired environment (like in your 2nd solution), though if you don't want to define an extra function in each module you can useexec
:import ui import my_customers def do_customers(sender): exec("import ui; ui.load_view('customers')", vars(my_customers)) # ...
-
@dgelessus, thank you. But I am so new, I have never tried the exec cmd before. I tried to understand it , reading and tried it in my code. Could not get it to work as expected. My 2nd solution works, I am trying to understand the advantage of your code. I am thinking if I have many views, I just define a setup() func for each view, and it will work fairly painlessly and uniformly.
-
If you are trying to make your code cleaner, using exec is probably not what you want.
Make a
Customer
class, which can be in a separate file. Then all the variables and methods are encapsulated in the class. You could also or instead make a CustomerView, which extendsui.View
. In that case you would just instantiate a CustomerView and prsent it in yourdo_customers
action.Inside
__init__
of CusomerView, you wouldui.load_view()
, then you need to set all of the actions to point to yourself
methods, since pyui cant refer to instance methods. I'm sure there are a few examples around. -
I will just mention that for debugging purposes I am calling
reload('customers') etc for my .py files that I call setup() in. Just to be sure -
heres an example using classes.
my_customers.py
would contsin the following.import ui,console class CustomerView(ui.View): def __init__(self): v=ui.load_view('my_customers.pyui') v['button1'].action=self.myaction self.add_subview(v) def myaction(self,sender): console.hud_alert('pushed')
where
my_customers.pyui
contains a single button named button1 in this case. then your main script would becomeimport ui import my_customers def do_customers(sender): c = my_customers.CustomerView() c.present('sheet') #other options: have your main view be a navigationview, then push this onto the main view, rather than presenting a new view. if __name__ == '__main__': v = ui.load_view('my_main_view') v.right_button_items = [ui.ButtonItem('Customers', None , do_customers)] v.present('sheet')
-
@JonB, thank you. I have tried your class method, I still fail to see the advantages over what I did in my #2nd way. I feel it's more clear and concise, but again I am a beginner and trying to learn. Maybe it's a hair this way or that way, maybe not. Maybe I am just missing the point! But I am willing to learn.
-
Your method will work fine.
As you start getting into more advanced ui programming, you'll need custom View classes to do any sort of touch handling, advanced layouts (such as resizing when
flex
doesn't do what you want it to), auto-resizing for the keyboard frame, etc.It can also simplify some really complicated views, by allowing you to "flatten" things with convienence variables. For instance you might have a textview inside a scrollview which is inside another view -- you could just have a variable inside your class that refers to the textview, rather than having to get to it via myview['panel']['scrollview1']['textview1'], etc.
This becomes a little more important when building View's from scratch rather than from the ui editor. -
@JonB, thanks again for taking time to respond. I see your point. Everything I have done to date is simple, but also didn't take long to get get out of control using the one .py file. I guess another advantage with the class approach will be the ability to easily cache variables. Again, thank you for the guidance.
-
@JonB, is the below code a valid approach? many of my screens will use many of the same utility functions. which i can see can be put into the base class. i think it will further clean up my code. also i was not clear why in your example you loaded the subview in the init(). is just a speed thing? or more the idea that the subview would be arould for the life of the application? but i hope i am moving in the right direction, i feel i am.thanks
import ui class myui(ui.View): def __init__(self, view_name, style = 'sheet'): self.display_style = style self.view = ui.load_view(view_name) def display(self): self.view.present(self.display_style) def util1(self): pass def util2(self): pass class customer_view(myui): def __init__(self): super(customer_view, self).__init__('customer_view') if __name__ == '__main__': c = customer_view() c.display()
-
Of course should be obvious I guess, is fairly easy to implement some type of themeing (was not to me) by doing things this way (classes), I can see it now. Can iterate over the view.subview items and check the type() of each item and set the attributes appropriately. I have stopped trying to make my example app. Trying to abstract the base class as much as possible (if that's the right term). I am sure because of my inexperience, But I am baffled that the left and right hand menu button items are truples. I really wanted to be easily to append a button to the left or right. It appears I can't just do an append() of a ui.ButtonItem, have to copy the current items then do a new assignment. At least I think it's that way. Didn't want to ask omz about this as it seems he has enough to deal with regarding the new Beta.
-
v.right_button_items+=(ui.ButtonItem(........),)
works if you are just adding to end. It is a tuple (immutable) not a list, so you can add to it like this, but can't use list methods.
you don't need to go crazy trying to find the optimal way to partition things... Get something working, and you'll soon see whether you need to repartition.
One drawback with using classes is that after you load the pyui, you need to manually set all of the callback
action
values, since you can't referee instance methods in the ui editor. Your original method would have been better for that.The reason my example added it to a subview was so that you can treat your view as View, not just as a generic class which contains a View.
-
@JonB, again thanks about v.right_button_items+=(ui.ButtonItem(........),), will try it in the morning. i am not sure what you meant about this statement - 'One drawback with using classes is that after you load the pyui, you need to manually set all of the callback action values'? I was able to set the action in the .pyui file for items. just wrote in the action field, self.my_action. This called my_action with no problems. Maybe, i did not get your meaning. I am also thinking that i could modify actions with a sort of late binding by assigning a bound method. I am not sure really, just my tests with the v.right_button_items.... leads me to believe so... As I say, i haven't tried it all, but i did try the action in the .pyui file and It worked with no problems, maybe you are talking about something else.
-
I stand corrected... I was thinking of cases where the ui is specified as a custom view... In that case self does not yet exist. Calling loadview from within an instance method does expose self to load iew, as you found.
-
@JonB, I am having difficulty getting your example of v.right_button_items += , working. But will not bother you about it. I will keep working on it. I don't expect to be spoon fed. I think I am just over thinking it. Enjoy your weekend.
-
The right Hand side must be a tuple, so don't miss that extra comma inside the parens.
(blah)
is not a tuple, while(blah,)
is -
Hmmm, spoiler alert :) thanks @JonB. That pesky comma was the the problem. However, to get it to work had to have a if... Maybe that's implied in your response. I think this is correct ;
def menu_button_left(self, name, action): v = self.view btn = ui.ButtonItem(name, None, action) if v.left_button_items: v.left_button_items += (btn,) else: v.left_button_items = [btn]