Forum Archive

One function for all ui.buttons?

Bjucha

Hi is there a way to have one function for all 4 buttons in my code that returns different depending on what button was pressed?

As of now I have four functions one for each button, but I thought it would look nicer if there was ony one function

import ui
def button_tapped(sender):
        lb1.background_color = 'blue'
        lb1.text = 'Blue'

def button2_tapped(sender2):
    lb1.background_color = 'red'
    lb1.text = 'Red'

def button3_tapped(sender3):
    lb1.background_color = 'yellow'
    lb1.text = 'Yellow'

def button4_tapped(sender4):
    lb1.background_color = 'green'
    lb1.text = 'Green'

w,h = ui.get_screen_size()
bh = 50
bw = 100
mg = 5
view = ui.View(name = 'Color fun', bg_color = 'darkgrey', frame = (0,0,w,h))
view.present('screen')

lb1 = ui.Label(name = 'Label1', bg_color = 'silver')
lb1.frame = (300,100,200,100)
lb1.border_color = 'black'
lb1.border_width = 1
lb1.alignment = ui.ALIGN_CENTER

button = ui.Button(title = 'Blue', alignment=ui.ALIGN_CENTER, bg_color = 'white', font_color = 'black')
button.frame = (200,900,100,50)
button.tint_color = 'black'
button.border_width = 1
button.action =button_tapped

button2 = ui.Button(title = 'Red', alignment=ui.ALIGN_CENTER, bg_color = 'white')
button2.frame = (300,900,100,50)
button2.tint_color = 'black'
button2.border_width = 1
button2.action = button2_tapped

button3 = ui.Button(title = 'Yellow', alignment=ui.ALIGN_CENTER, bg_color =  'white')
button3.frame = (400,900,100,50)
button3.tint_color = 'black'
button3.border_width = 1
button3.action = button3_tapped

button4 = ui.Button(title = 'Green', alignment=ui.ALIGN_CENTER, bg_color = 'white')
button4.frame = (500,900,100,50)
button4.tint_color = 'black'
button4.border_width = 1
button4.action = button4_tapped

view.add_subview(button)
view.add_subview(lb1)
view.add_subview(button2)
view.add_subview(button3)
view.add_subview(button4)

# I would like it something like:
def button_tapped(sender):
    if sender == 1:
        return lb1.bg_color = 'blue'
    if sender == 2:
        return lb1.background_color = 'red'
    if sender == 3:
        return lb1.backgground_color = 'green'
    if sender == 4:
        lb1.background_color = 'yellow'

But can't get it to work.
Grateful for any advice

ccc
def button_tapped(sender):  # sender is the button itself so you can directly access it's title
    lb1.background_color = sender.title.lower()
    lb1.text = sender.title.title()
Bjucha

@ccc thanks for the answer, gonna try it later

ccc
import ui

w, h = ui.get_screen_size()
bw = 100
bh = 50


def button_tapped(sender):
    label.bg_color = sender.bg_color
    label.text = sender.title
    label.text_color = sender.tint_color


def make_button(title, screen_x):
    button = ui.Button(
        action=button_tapped,
        alignment=ui.ALIGN_CENTER,
        bg_color=title.lower(),
        border_color='black',
        border_width=1,
        frame=(screen_x, h - 124, bw, bh),
        tint_color='white',
        title=title)
    # it seems to be necessary to reset the frame
    button.frame = (screen_x, h - 124, bw, bh)
    return button


label = ui.Label(
    alignment=ui.ALIGN_CENTER,
    bg_color='silver',
    border_color='black',
    border_width=1,
    frame=(300, 100, 200, 100),
    name='Label')

button1 = make_button(title='Blue', screen_x=200)
button2 = make_button(title='Red', screen_x=300)
button3 = make_button(title='Yellow', screen_x=400)
button3.tint_color = 'black'  # hard to read white text on a yellow background
button4 = make_button(title='Green', screen_x=500)

view = ui.View(name='Color fun', bg_color='darkgrey', frame=(0, 0, w, h))
view.add_subview(label)
view.add_subview(button1)
view.add_subview(button2)
view.add_subview(button3)
view.add_subview(button4)
view.present('screen')
Bjucha

@ccc Ah cool, this looks much better than my code, thanks alot, gonna implement it and see how it looks

Phuket2

Oh, ok. @ccc beat me to it. I have a slightly different approach for the button building. Basically learnt from @ccc anyway.

It's not better way what I am doing, but you can see other ways you can do it.

import ui

def create_btn(id, *args, **kwargs):
    btn = ui.Button(**kwargs)   # ---> passes the kwargs to the Button __init__ (2.7 or 3.5)
    btn.id = id                 # ---> adds the attribute id to ui.Button
    return btn

def button_action(sender):
    # using this func for all buttons. Could use the id to determine what to do for which btn
    print(sender.id, sender.title)

if __name__ == '__main__':
    v = ui.View(frame=(0, 0, 200, 300), bg_color='white')
    btn1 = create_btn(1, title='OK', border_width=.1, frame=(50, 50, 50, 100),
        action=button_action, bg_color='red', tint_color='white', corner_radius = 3)
    btn1.width=100    # the width is not set by the frame kwargs, i think because,
                      # size_to_fit is automatically called when the button is created
                      # i cant remember, maybe theres a way to override that so you dont need
                      # the extra call to set the width 

    btn2 = create_btn(2, title='Cancel', border_width=1, frame=(50, 90, 100, 200),
        action=button_action, bg_color='green', tint_color='white', corner_radius = 3)
    btn2.width=100

    v.add_subview(btn1)
    v.add_subview(btn2)
    v.present('sheet')
ccc

@Phuket2 it is both width and height that you have to watch out for.

Phuket2

@ccc , yeah. I thought about that after seeing your post. I wrote my post without seeing yours. It's a tricky one for ole, because you probably want at least the height change based on font, but if you supply a frame maybe that should be explicit and should be honoured. Not sure

ccc

You can probably get what you want by messing with button.flex.

Phuket2

@ccc , oh just had a thought. It's not a new thought, just forgot about it. But a size_font_tofit() method would be perfect. But it's been discussed before. Gets tricky across all fonts, esp fonts like Zaph Chancery etc...I have tried many times in the past I think just with the length. Only using the ui methods. But I guess using objc it may be a different story given you have access to all the fonts metrics. But it's beyond me

zipit

Everything important has already been said. But just for completeness: I think the pythonic thing to do would be to use list comprehensions here as it would result in shorter and less imperative code. Building on cccs example:

import ui

w, h = ui.get_screen_size()
bw = 100
bh = 50


def button_tapped(sender):
    label.bg_color = sender.bg_color
    label.text = sender.title
    label.text_color = sender.tint_color
    print(label.bg_color)


def make_button(title, screen_x, super_view):
    button = ui.Button(
        action=button_tapped,
        alignment=ui.ALIGN_CENTER,
        bg_color=title.lower(),
        border_color='black',
        border_width=1,
        frame=(screen_x, h - 124, bw, bh),
        tint_color='white',
        title=title)
    # it seems to be necessary to reset the frame
    button.frame = (screen_x, h - 124, bw, bh)
    super_view.add_subview(button)
    return button


label = ui.Label(
    alignment=ui.ALIGN_CENTER,
    bg_color='silver',
    border_color='black',
    border_width=1,
    frame=(300, 100, 200, 100),
    name='Label')

view = ui.View(name='Color fun', bg_color='darkgrey', frame=(0, 0, w, h))
view.add_subview(label)
buttons = {color: make_button(title=color, screen_x=200 + 100 * i,
                              super_view=view)
           for i, color in enumerate(['blue', 'red', 'yellow', 'green'])}
buttons['yellow'].tint_color = 'black'
view.present('screen')