Forum Archive

Simple UI tutorial?

Bjucha

Hi

Is there a tutorial for the ui, like how to create labels and how to determinate their position and so on. Found many examples and programs for the ui but I would like something very simple to start with since im very new at this.

I would like to write the code and not use the ui designer if possible

JonB

Have you looked at the ui docs in the app? The intro section has a simple tutorial and detailed explanation , which is good to understand before going any further.

There is this repo, which has several tutorials. I dont't think they are necessarily "in order",
https://github.com/humberry/ui-tutorial

Bjucha

Thx have to look at it. Is there a way to see the code for the ui creator?
Like if I create a label can I see the code for it?

Brando

Yes after creating a label there are many different attributes for it. The help menu was vital for my learning of the ui module. You can use: (labelname).text to set the text of the label and (labelname).name for the name of the label, I'm pretty sure this is read only but it's helpful with button to determine which one is being pressed. Most other helpful parameters can be set within the definition of the label. The ui editor is easier to use, and look at the built-in examples, they are helpful.

JonB

The pyui files created by the ui editor are simple .json files. You can rename the file to json, and see what is inside, or simply open(filename).read(). The json only encodes the non-default parameters, if memory serves.

You can also open Modules/Python3/site-packages/ui.py to see how these get loaded, but other than some special encoding of colors, mostly this just loads the attribs in the json for each component, then adds a subview to its parent.

ramvee

Hi @Bjucha ,
I am a beginner too.
And made this small label program to
understand UI Module and Label Creation with position.
I find UI Module's learning curve steep, but UI Module is vital to use Pythonista on the iOS devices.
Hope this helps

# Learning Alignment Options In UI
# Pythonista
# Flex LRTBWH
import ui

w,h = ui.get_screen_size()
h = h - 64
view = ui.View(name = 'Flex', bg_color = 'lightyellow', frame = (0,0,w,h))
#view.flex = 'WH'
# label height and button width
bh = bw = 80
# margin
mg = 10


lb1 = ui.Label(name = 'Label1', bg_color = 'yellow', frame =(mg,mg,bw,bh))
lb1.border_color = 'black'
lb1.border_width = 1
lb1.flex = 'RB'
lb1.alignment=1
lb1.text = lb1.flex

lb2 = ui.Label(name = 'Label2', bg_color = 'yellow', frame =(w-(bw+mg),mg, bw,bh))
lb2.border_color = 'black'
lb2.border_width = 1
lb2.flex = 'LB'
lb2.alignment=1
lb2.text = lb2.flex

lb3 = ui.Label(name = 'Label3', bg_color = 'yellow', frame =(mg,h-(bh+mg),bw,bh))
lb3.border_color = 'black'
lb3.border_width = 1
lb3.flex = 'RT'
lb3.alignment=1
lb3.text = lb3.flex

lb4 = ui.Label(name = 'Label4', bg_color = 'yellow', frame =(w-(bw+mg),h-(bh+mg),bw,bh))
lb4.border_color = 'black'
lb4.border_width = 1
lb4.flex = 'LT'
lb4.alignment=1
lb4.text = lb4.flex

# center
lb5 = ui.Label(name = 'Label5', bg_color = 'yellow', frame =((w-bw)*.5,(h-bh)*.5,bw,bh))
lb5.border_color = 'black'
lb5.border_width = 1
lb5.flex = 'LRTB'
lb5.alignment=1
lb5.text = lb5.flex

view.add_subview(lb1)
view.add_subview(lb2)
view.add_subview(lb3)
view.add_subview(lb4)
view.add_subview(lb5)

view.present('screen')
ccc

@ramvee This example is great!

One of the things that I found when I first started using the ui module was that when I did not use .pyui files then my code got long and repetitive. Often I want all my ui elements to share a common look and feel (bg_color, border_color, border_width, etc.) and I only need to set a few unique values like name and frame. To reduce this code bloat, I recommend creating a make_label() function that puts all the common stuff inside and accepts as parameters from the outside the unique stuff...

# Learning Alignment Options In UI
# Pythonista
# Flex LRTBWH
import ui


def make_label(name, frame):
    return ui.Label(
        alignment=1,
        bg_color='yellow',
        border_color='black',
        border_width=1,
        frame=frame,
        flex=name,
        name=name,
        text=name)


w, h = ui.get_screen_size()
h -= 64
bh = bw = 80  # label height and button width
mg = 10  # margin
view = ui.View(name='Flex', bg_color='lightyellow', frame=(0, 0, w, h))
view.add_subview(make_label(name='RB', frame=(mg, mg, bw, bh)))
view.add_subview(make_label(name='LB', frame=(w - (bw + mg), mg, bw, bh)))
view.add_subview(make_label(name='RT', frame=(mg, h - (bh + mg), bw, bh)))
view.add_subview(make_label(name='LT',
                            frame=(w - (bw + mg), h - (bh + mg), bw, bh)))
view.add_subview(make_label(name='LRTB',
                            frame=((w - bw) * .5, (h - bh) * .5, bw, bh)))
view.present()
ramvee

@ccc Wow! God Bless You!
Superb And Compact As Always.

Bjucha

Thank you everyboy. I this is very helpful!

Ti Leyon

Hi @Bjucha try to look at the first script in this post: https://forum.omz-software.com/topic/3964/unipage-as-a-bridge-between-kivy-and-pythonista. It defines simple ways to put basic ui elements at any position on the screen programmatically.

Bjucha

Thx for all the info, will look at it all
Im not very good with programming but it's fun to learn and imporve my basic skills

Bjucha

@ramvee hello I have a question for you
This part of your code:

w,h = ui.get_screen_size()
h = h - 64
view = ui.View(name = 'Flex', bg_color = 'lightyellow', frame = (0,0,w,h))
#view.flex = 'WH'
# label height and button width
bh = bw = 80
# margin
mg = 10

Is about the size of the ui. W,h is width and height ?
But why is h = -64?
is bh and bw borderheight and borderwidth?
And finally mg what is that?

ramvee

@Bjucha Sorry, you can remove that line.
i used to think that screensize measures the total screen including the title bar.
So i used to subtract 64 from height to compensate for title bar height.

bw and bh are just width and height of button, or label in this case.

mg is margin between the top, bottom and side edges from screen, from where the labels are..

You can fool around with values to see what happens. 😊

Bjucha

@ramvee Hello Just wanna say thanks for your template.
I have now been able to create labels and buttons thanks to you

ramvee

@Bjucha You are welcome.
Just sharing what i learned from talented folks in this forum.
Pythonista is an excellent program to learn python.. it's just that UI takes time.
@omz #Respect

ihf

I would like to print to a view rather than the console so that I can control fonts size, etc. Could someone give me a snippet of code does this? I just want a full screen view that displays the text and a way to close the view.

enceladus

@ihf See this
https://forum.omz-software.com/topic/3642/print-console-in-textview-or-scrollview

Phuket2

@ihf, I wrote the below in a few mins (I am still a novice). My point is sometimes its worth doing yourself. Even if you have to ask some questions along the way. Of course its good for learning, and because you write yourself its a lot easier for you to get your exact solution. I still copy code though, but I often have a go at it myself also.

Anyway, from what you describe, I think the below does what you want or at least is a good starting point.

import ui


class MyConsole(ui.View):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.tv = None
        self.make_view()

    def make_view(self):
        tv = ui.TextView(frame=self.bounds,
                         flex='wh',
                         font=('Arial Rounded MT Bold', 24),
                         editable=False,
                         )
        self.tv = tv
        self.add_subview(self.tv)

    def write_line(self, txt):
        self.tv.text += "{}\n".format(txt)


if __name__ == '__main__':
    f = (0, 0, ui.get_screen_size()[0], ui.get_screen_size()[1])
    v = MyConsole(frame=f, name='My Full Sceen Console')
    v.present(style='', animated=False)
    for i in range(100):
        v.write_line('line-{}'.format(i))
PeterG

@ccc very nice example.
What and why flex=name ? Can't find the meaning of it

ihf

@Phuket2 First of all, thank you very much for writing this script...I think it is precisely what I need. My only problem is I am using PrettyTable which is apparently formatting for a fixed width font so I need to play with the ui view options to get things to line up. Second, while I agree completely that doing this myself is the best way to learn python I am struck by the fact that it will take me awhile to even understand your code much less write it from scratch on my own. So, thanks again for giving me working code and something to study.

ccc

@PeterG http://omz-software.com/pythonista/docs/ios/ui.html#view Under View Attributes see View.flex... Hint, 'wh' is not a name.

Phuket2

@ihf, for the font you could just use Menlo or another mono spaced font (Menlo, is what is used in the console by default I think) . Anyway, I was not critising you at all. I just has similar problems when I started. There is a smalll bump to get over using the ui module, but it does fall into place pretty quickly. I did not try writing from prettytable into the TextField , However I can't see why it should not work. The only think that comes to mind could be you getting extra line feed chars in the text. If that were to happen you could do a replace on those chars either in the write_line method, or before you pass the string to write_line. Anyway, let me know if you have a problem, If will help if I can

python tv = ui.TextView(frame=self.bounds, flex='wh', font=('Menlo', 24), editable=False, )python

Phuket2

@ihf, I just updated the example to have a copy to clipboard and clear methods and menu items. Not sure they are useful, but good to see how to add menu Items anyway, if you haven't played with them yet.
My example is not as compact looking as it could be, but I try and following the PEP8 style now. Eg, only one import per line, 2 lines after the imports etc.

import ui
import clipboard
import console


class MyConsole(ui.View):
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.tv = None
        self.make_view()

    def make_view(self):
        tv = ui.TextView(frame=self.bounds,
                         flex='wh',
                         font=('Menlo', 24),
                         editable=False,
                         )
        self.tv = tv
        self.add_subview(self.tv)

        '''
        Create 2 ui.ButtonItem to insert into the menubar.  ButtonItem's are
        one of those pesky ui Items that are not subclassed from ui.View
        Its not a big deal, just good to know they differ from ui.Button.
        You can see in the docs.

        Below, I am adding the 2 menu buttons to the right side as it seems to
        make sense. There is a method left_button_items also.
        '''
        mbtn_clear = ui.ButtonItem(title='Clear', action=self.clear_console, tint_color='red')
        mbtn_copy = ui.ButtonItem(title='Copy', action=self.copy_console)
        self.right_button_items = (mbtn_clear, mbtn_copy)

    def write_line(self, txt):
        self.tv.text += "{}\n".format(txt)

    def clear_console(self, sender=None):
        '''
        sender is set to None so sender is not required to call this method.
        The action from the menu ButtonItem needs to see it there though.
        But it means you can call this method on the object withouut having
        to pass a sender.  i.e if youwanted to clear the console from your
        code rather than the menu button action.
        ie. obj.clear_console() will work.
        Same goes for the copy_console method below.
        '''
        self.tv.text = ""

    def copy_console(self, sender=None):
        clipboard.set(self.tv.text)
        console.hud_alert('{} characters copied.'.format(len(self.tv.text)))


if __name__ == '__main__':
    f = (0, 0, ui.get_screen_size()[0], ui.get_screen_size()[1])
    v = MyConsole(frame=f, name='My Full Sceen Console')
    v.present(style='', animated=False)
    for i in range(100):
        v.write_line('line-{}'.format(i))