Forum Archive

[Share] Creating grid for using with ui

Phuket2

Sorry, this has been done to death. By me also before. It's just about a small function (get_grid_rc) to create a grid to use with ui.Views. But its always worth bring up I think as there are always new users.
Grids can be represented/determined in many ways depending on your needs. I think the one I have done here is a pretty common need. Unfortunately the test code around the function sort obscures how simple it is. I am not saying this is the best way to do this btw. It's just a way. Again, to try and keep this simple, I did not deal with full screen. It's not thats its so difficult, but different ways to handle that case. Anyway, I hope someone finds it useful.

import ui

'''
get_grid_rc, can be a handy snippet to get a list of
ui.Rects for your view, given a width, height, num rows and num cols.
When doing ui stuff you often need this type of functionality.
I am sure its not the fastest in speed... Just want some small
function that does not eclipse your code.
w & h could be evaluated in the list comp, removing a line,
but thats seems like it would be a step too far
Also, get_grid_rc is not dealing with divide by zero errors.
Expects you pass valid params. eg. all params need to be non-zero (positive)!
While returning ui.Rects here, could easily change it to return a
list of ui.Buttons etc... However seems like a list of ui.Rects is
the best for an example.
As simple as this example is, it can be useful in many ways. eg. you
could call this in a custom views layout method to resize objects.
'''


def get_grid_rc(width, height, rows, cols):
    '''
    returns a single linear list of ui.Rects. l[0] will be the most top left
    rect. l[-1] will be most bottom right rect.
    '''
    w, h = (width / cols, height / rows)
    return [ui.Rect(w * j, h * i, w, h) for i, _ in enumerate(range(rows))
            for j, _ in enumerate(range(cols))]

if __name__ == '__main__':
    f = ui.Rect(0, 0, 320, 480)
    v = ui.View(frame=f)

    # simple test action callback for our ui.Buttons. All use this func.
    def btn_action(sender):
        print(sender.title)

    # get the grid and use it as you like.  I have used it to add ui.Buttons
    # to a view. 6 rows x 7 columns for the size of the whole view.
    # this is a normal grid to make month view on a calender
    r_grid = get_grid_rc(v.frame.width, v.frame.height, 6, 7)

    # iterate over the r_grid with enumerate. each iteration we get the index,
    # and the ui.Rect.
    for i, r in enumerate(r_grid):
        btn = ui.Button(name=str(i), title=str(i),
                        bg_color='cornflowerblue', border_width=.5,
                        border_color='white', tint_color='black',
                        action=btn_action)
        btn.frame = r
        v.add_subview(btn)

    v.present(style='sheet', animated=False)
ccc
import ui
'''
get_grid_rc, can be a handy snippet to get a list of
ui.Rects for your view, given a width, height, num rows and num cols.
When doing ui stuff you often need this type of functionality.
I am sure its not the fastest in speed... Just want some small
function that does not eclipse your code.
w & h could be evaluated in the list comp, removing a line,
but thats seems like it would be a step too far
Also, get_grid_rc is not dealing with divide by zero errors.
Expects you pass valid params. eg. all params need to be non-zero (positive)!
While returning ui.Rects here, could easily change it to return a
list of ui.Buttons etc... However seems like a list of ui.Rects is
the best for an example.
As simple as this example is, it can be useful in many ways. eg. you
could call this in a custom views layout method to resize objects.
'''


def get_grid_rc(width, height, rows, cols):
    '''
    a generator of frame tuples.  l[0] will be the most top left rect.
    l[-1] will be most bottom right rect.
    '''
    w, h = (width / cols, height / rows)
    return ((w * j, h * i, w, h) for i in range(rows) for j in range(cols))


if __name__ == '__main__':
    f = ui.Rect(0, 0, 320, 480)
    v = ui.View(frame=f)

    # simple test action callback for our ui.Buttons. All use this func.
    def btn_action(sender):
        print(sender.title)

    # get the frames and use them as you like.  I have used it to add
    # ui.Buttons to a view. 6 rows x 7 columns for the size of the whole view.
    # this is a normal grid to make month view on a calender
    frames = get_grid_rc(f.width, f.height, 6, 7)

    # iterate over the frames with enumerate. each iteration we get the index,
    # and the frame tuple.
    for i, frame in enumerate(frames):
        btn = ui.Button(name=str(i), title=str(i), action=btn_action,
                        bg_color='cornflowerblue', border_width=.5,
                        border_color='white', tint_color='black')
        btn.frame = frame
        v.add_subview(btn)

    v.present(style='sheet', animated=False)
Phuket2

@ccc , I had thought about using a generator. In my example I am just iterating over them so basically disgarding them, so the generator approach makes more sense. In the event you wanted to keep them around then the list works. Regardless I will update my snippet to yours, I can see I stupidly used enumerate unnecessarily. Makes me glad I posted it now. Nice to have some of these so called simple functions nailed down. One of the reasons I screwed it up is because I had it stored as a snippet without using comprehension. I need to slow down and think sometimes.

ccc

Staring at someone else's code and optimizing it is so much easier then actually writing new code. I can do the former while riding the subway but the latter takes both time and focus. Please keep up the great work... I still sense that you have a great hotel calendaring app in the back of your head that informs many of your examples.

Phuket2

@ccc, the hotel app idea is dead. My friend that I wrote the Excel/VBA version for is not in the hotel business anymore. We are Actualling sharing a nice big house together now in Pattaya. A Danish guy, we have been friends for many years. It's a little bit like the old show the odd couple, us to living together, but we still have fun :)

So no real push for me to do booking thing any more. But I still would like to make a pretty good calendar picker( I honestly hate the Apple DateTime Picker). I have made some before, but I should be able to make something better now. At least I hope so. The other thing I will get back to is my voting app. I always go wrong, as I try to make frameworks instead of just getting on and coding something with brute force just to get it done. Pretty or not. It's funny I should have those problems at this age. I didn't have it when I was younger. I was very aware and sensitive to commercial realities, get it done and out the door! I guess without that need, it changes you.

Hmmm, just after announcing I should be better. I need to ask something embarrassing. I looked at this last night, for some reason I could not get my head around it.

Below in the generator you modified, I have added x in the return tuple. I can't figure out how to get x to just be a linear counter ie. 0 to (rows * cols)-1.
I have looked at it too long so I have decided to ask....My feeling it should be something simple that can be done in place and should not be apart of the comp loops....
just adding x doesn't make much sense as it appears below, but makes more sense if you are creating objects in the generator rather than a tuple.
Any help appreciated.

    return ((w * j, h * i, w, h, x) for i in range(rows) for j in range(cols))