Forum Archive

Input buttons

Bumbo Cactoni

How would I do a button on the screen that creates an input when pushed (preferably using scene module, but ui also works)? For example, there are three buttons on-screen, red, green, and blue. If i push the red button, it does the same as if I typed "red" into the input bar.

mcriley821

What do you mean by input bar? Like the Pythonista console?

mikael

@Bumbo-Cactoni, tiny example below, using ui because scene does not really have an ”input bar”, and mixing the two is not really the best way to start learning about them.

import ui


class MyApp(ui.View):

    def __init__(self, **kwargs):
        self.background_color = 'black'
        super().__init__(**kwargs)

        self.tf = ui.TextField(
            frame = (0, 0, 200, 40),
        )

        self.b_red = ui.Button(
            title='red',
            tint_color='black',
            background_color='lightgrey',
            action=self.action,
        )
        self.b_red.frame = (0, 0, 100, 30)

        self.add_subview(self.tf)
        self.add_subview(self.b_red)

    def action(self, sender):
        self.tf.text += sender.title

    def layout(self):
        self.tf.center = self.bounds.center()
        self.b_red.center = self.bounds.center()
        self.b_red.y = self.tf.y + 70


MyApp().present('fullscreen')
Bumbo Cactoni

@mikael
Thank you!

@mcriley821
I meant like @mikael answered. Like the Pythonista console.

mcriley821

@Bumbo-Cactoni well which is it, the textField or the console? 😂

When I say console I mean when you swipe left and go to the screen that has the word “Console” at the top. The input is what you’d usually type on this screen.

There’s ways to make your own buttons/toolbars and ui stuff on the actual Pythonista app itself, and not on a view you present. I was just trying to clarify.

I’m glad @mikael answered your question the way you needed though! 😎

cvp

@Bumbo-Cactoni Nicer (not Pythonically speaking) than @mikael 's one 🙄 and ok for all your TextFields, with buttons in keyboard, not in view

from   objc_util import *
import ui

def key_pressed(sender):
        import ui
        from objc_util import ObjCClass
        tv = sender.objc_instance.firstResponder()  # associated TextView
        # get actual cursor position                    
        cursor = tv.offsetFromPosition_toPosition_(tv.beginningOfDocument(), tv.selectedTextRange().start())
        tv.insertText_(sender.title)    

class MyView(ui.View):
    def __init__(self, pad, *args, **kwargs):
        #super().__init__(self, *args, **kwargs)    
        self.width = ui.get_screen_size()[0]            # width of keyboard = screen
        self.background_color = 'lightgray'#(0,1,0,0.2)
        self.h_button = 32  
        self.pad = pad

        # build buttons
        for pad_elem in self.pad:
            button = ui.Button()                                    # Button for user functionnality
            button.name = pad_elem['key']
            button.background_color = 'white'           # or any other color
            button.corner_radius = 5        
            button.font = ('<system>',self.h_button - 8)
            button.title = pad_elem['key']
            button.tint_color = button.title
            button.action = key_pressed
            retain_global(button) # see https://forum.omz-software.com/topic/4653/button-action-not-called-when-view-is-added-to-native-view
            self.add_subview(button)    
        self.layout()       

    def layout(self):
        import ui
        # supports changing orientation
        dx = 8
        dy = 2
        x0 = 15
        y0 = 10
        dx_middle = 25 
        y = y0
        x = x0
        w_button = (ui.get_screen_size()[0] - 2*x0 - 17*dx - dx_middle)/18
        for pad_elem in self.pad:
            nw = pad_elem.get('width', 1)
            wb = w_button*nw + dx*(nw-1)
            if (x + wb + dx) > self.width:
                y = y + self.h_button + dy
                x = x0
            button = self[pad_elem['key']]
            xb = x + dx_middle if (x+wb) > self.width/2 else x
            button.frame = (xb,y,wb,self.h_button)
            if button.title != '':
                font_size = self.h_button - 8
                while True:
                    d = ui.measure_string(button.title,font=(button.font[0],font_size))[0]+4
                    if d <= wb:
                        break
                    font_size = font_size - 1           
            button.font = (button.font[0],font_size)
            x = x + wb + dx
        self.height = y + self.h_button + dy    

@on_main_thread 
def AddButtonsToPythonistaKeyboard(pad=None):
    if not pad:
        pad = [
        {'key':'red','width':2},
        {'key':'green','width':2},
        {'key':'blue','width':2}]   
    # create ui.View for InputAccessoryView above keyboard
    v = MyView(pad)                                             # view above keyboard
    vo = ObjCInstance(v)                                    # get ObjectiveC object of v
    retain_global(v) # see https://forum.omz-software.com/topic/4653/button-action-not-called-when-view-is-added-to-native-view
    return vo

if __name__ == '__main__':  
    vo = AddButtonsToPythonistaKeyboard()

    v = ui.View()
    v.frame = (0,0,400,400)
    v.background_color = 'white'        
    tf1 = ui.TextField(frame=(10,50,200,32))
    ObjCInstance(tf1).textField().setInputAccessoryView_(vo)    
    v.add_subview(tf1)
    tf2 = ui.TextField(frame=(10,150,200,32))
    ObjCInstance(tf2).textField().setInputAccessoryView_(vo)    
    v.add_subview(tf2)
    v.present('sheet') 

cvp

@cvp said:

Nicer (not Pythonically speaking) than @mikael 's one

I was only humorous and you're to kind to upvote my post.

mikael

@cvp, no worries! If you said something nasty, I would know someone had hijacked your user account.