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.
[Lab] on the fly grid to help position ui elements
-
A func to return a flattened list using a list comprehension. Found it on stackoverflow. Acutually, I could have also written it, but i was looking to make sure there was not some other Python magic that could be done. Can be a useful func when you have a list of lists and you just want to iterate over them easily.
def flattened_list(lst): # flatten the list array, the code from stackoverflow return [item for sublist in lst for item in sublist]
-
Ok, here is an example using ui.Buttons. It's still a pretty generic example. But gets closer to my meaning.
But if you disregard the function grid_rc_ it's a line or 2. Again, this not necessarily a real world example (but it could be).# Pythonista Forum - @Phuket2 import ui, editor def grid_rc_(bounds, rows=1, columns=1): # a grid based on rows and columns # return a list of lists of ui.Rects r = ui.Rect(*bounds) w = r.width / columns h = r.height / rows rl = [] for i in range(rows): lst = [] for j in range(columns): lst.append(ui.Rect(j*w, h*i, w, h)) rl.append(lst) return rl def flattened_list(lst): # flatten the list array, the code from stackoverflow return [item for sublist in lst for item in sublist] class MyClass(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.make_view() def make_view(self): rows = 10 cols = 5 # get a flatten lst of the specified grid lst = flattened_list(grid_rc_(self.bounds, rows, cols)) for i, r in enumerate(lst): r = ui.Rect(*r.inset(5, 5)) btn = ui.Button(name=str(i), frame=r) btn.title = str(i) btn.border_width = .5 btn.corner_radius = btn.width * .1 btn.action = self.btn_action self.add_subview(btn) def btn_action(self, sender): print('btn -', sender.name) if __name__ == '__main__': _use_theme = False w, h = 600, 800 f = (0, 0, w, h) style = 'sheet' mc = MyClass(frame=f, bg_color='white') if not _use_theme: mc.present(style=style, animated=False) else: editor.present_themed(mc, theme_name='Oceanic', style=style, animated=False)
-
The same example, but getting a little stupid using list comprehensions. Actually I haven't tried this type of list comprehension before.
But ok, we need the method create_ui_obj, however if and when ui elements handle all kwargs, this method would not be required.Even though it's not so smart, it can spark some ideas.
# Pythonista Forum - @Phuket2 import ui, editor def grid_rc_(bounds, rows=1, columns=1): # a grid based on rows and columns # return a list of lists of ui.Rects r = ui.Rect(*bounds) w = r.width / columns h = r.height / rows rl = [] for i in range(rows): lst = [] for j in range(columns): lst.append(ui.Rect(j*w, h*i, w, h)) rl.append(lst) return rl def flattened_list(lst): # flatten the list array, the code from stackoverflow return [item for sublist in lst for item in sublist] class MyClass(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.make_view() def make_view(self): rows = 20 cols = 15 # another way, its a little crazy...but maybe @ccc likes it :) [self.add_subview(self.create_ui_obj(ui.Button, name=str(i),frame=f.inset(5,5), border_width=.5, corner_radius= 12, title=str(i), action = self.btn_action, bg_color='teal', tint_color='white')) for i, f in enumerate(flattened_list(grid_rc_(self.bounds, rows, cols)))] def create_ui_obj(self, ui_type, **kwargs): obj = ui_type() for k, v in kwargs.items(): if hasattr(obj, k): setattr(obj, k, v) return obj def btn_action(self, sender): print('btn -', sender.name) if __name__ == '__main__': _use_theme = False w, h = 600, 800 f = (0, 0, w, h) style = 'sheet' mc = MyClass(frame=f, bg_color='white') if not _use_theme: mc.present(style=style, animated=False) else: editor.present_themed(mc, theme_name='Oceanic', style=style, animated=False)
-
Hmm, to be size and orientation friendly the last post's make_view should be as below. Forgot to set the flex attr to 'lrtb'
def make_view(self): rows = 20 cols = 15 # another way, its a little crazy...but maybe @ccc likes it :) [self.add_subview(self.create_ui_obj(ui.Button, name=str(i),frame=f.inset(5,5), border_width=.5, corner_radius= 6, title=str(i), action = self.btn_action, bg_color='maroon', tint_color='white', flex='tlbrwh')) for i, f in enumerate(flattened_list(grid_rc_(self.bounds, rows, cols)))]
Edit: sorry another screw up. The flex should be 'tlbrwh', modified the code also 🙄
-
This is great @Phuket2, exactly what I was looking for. Just one question. Do you know what I need to change to make this work in Python 2?
I’m getting the error:
in __init__ super().__init__(*args, **kwargs) TypeError: super() takes at least 1 argument (0 given)
I’ve had a bit of a Google and played around. I can get it to run in Python 2 if I comment out the line:
super().init(*args, **kwargs)
But the resulting grid of buttons doesn’t look the same as with Python 3. The button widths collapse down to a minimum size. -
super().init(*args, **kwargs)
ui.View(self, *args,**kwargs)
-
Thanks for your quick response @JonB. If I replace
super().init(*args, **kwargs)
with
ui.View(self, *args,**kwargs)
it runs but I just get a blank screen.
-
@niz Calling
super()
without any arguments only works in Python 3. The equivalent Python 2 code issuper(<classname>, self)
, where<classname>
is the name of the class that you're currently in. This version ofsuper
works on both Python 2 and 3.Note that you have to write the class name in the
super
call by hand. You cannot usetype(self)
orself.__class__
- if you do, thesuper
call won't work properly. (See this Stack Overflow question.) -
@dgelessus Thank you. This works perfectly. When I’d Googled this I found a couple of examples that said to add <classname> but they neglected to mention you also needed self.
-
@niz whoops, i meant to type
ui.View.__init__(self, *args, **kwargs)