Move the commented line to the second button.center and the button moves. Why?presumedly due the the .width and .height statements.....
import ui v = ui.View() v.present('full_screen') button = ui.Button (title='button') v.add_subview(button) button.background_color = 'white' #button.center =(100,100) button.width= 360 button.height=100 button.center=(100,100)```
I simply want to position a button at a predictable position on screen (x,y) and have it stay there. What am i doing wrong?
@boo , the below is using flex. If you change the size or the style, the button is always centered. The best way to understand flex is to use the designer in Pythonista (Create a UIFile).
# Pythonista Forum - @Phuket2 import ui class MyClass(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.make_view() def make_view(self): btn = ui.Button(frame=(20, 20, 100, 32)) btn.border_width = .5 btn.title = 'hello' btn.bg_color = 'orange' btn.corner_radius = 6 btn.tint_color = 'white' btn.center = self.bounds.center() btn.flex = 'lrtb' self.add_subview(btn) if __name__ == '__main__': w, h = 900, 800 f = (0, 0, w, h) style = 'sheet' mc = MyClass(frame=f, bg_color='white') mc.present(style=style, animated=False)
Edit: if you remove the line
btn.center = self.bounds.center()
The button will stay in it's position based on the frame passed. But the flex attr is making that possible.
@boo here is a slightly different way. It's not using flex, it's using the layout callback(look at custom views in the help file). Is also a valid way to position your objects in a view. Ui Module is so flexible. Maybe the flexibly gives the idea it's hard. But it's not really. Everything is so well constructed, it normally just works very well.
# Pythonista Forum - @Phuket2 import ui class MyClass(ui.View): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.make_view() def make_view(self): btn = ui.Button(name='my_btn', frame=(20, 20, 100, 32)) btn.border_width = .5 btn.title = 'hello' btn.bg_color = 'orange' btn.corner_radius = 6 btn.tint_color = 'white' #btn.center = self.bounds.center() #btn.flex = 'lrtb' self.add_subview(btn) def layout(self): self['my_btn'].center = self.bounds.center() if __name__ == '__main__': w, h = 330, 600 f = (0, 0, w, h) style = 'sheet' mc = MyClass(frame=f, bg_color='white') mc.present(style=style, animated=False) ``` Edit: also the last 2 examples should be orientation friendly also. Not a big deal, but important.
Thanks for your help.
It seems you use:
to position the button. On the website, the basic example for Pythonista ui used:
Can you explain differences between frame and center attributes, as relates to a subview (in this case a button)
@boo , hmmm. I will try. It's not easy to say in words though. But the frame is the x, y, width, height of the object. So btn = ui.Button( frame=(0, 0, 100, 32) ) creates a ui.Button with a width of 100 and a height of 32. The x, y will be 0.
So if you set a button for example as above, you can adjust the x, y, width, height in subsequent calls.
btn.x = 100
btn.y = 150
btn.width = 400 etc..
So setting the frame is just a expedient way to set the 4 attrs (x, y, width, height) at one time.
Normally it's best to refer to the area/Rect/interior of an ui object by its bounds. Create a ui object with frame and refer to the interior of the object with bounds. For a button for example, the frame and bounds are equal I think. But a ui.View that has a menu for example the frame and bounds will be different. But what is nice, all the ui objects are subclassed from ui.View (almost all) , so you can just use the same technique to refer to bounds or frame. It should just work.
Sorry if the above is not clear. Not easy to explain
Thanks again. Looks like the example provided in the docs had me using button.center, button.height and button.width, instead of just button.frame.
@boo , I understand what you mean. The example is just one way to do it. I am sure in a few days this will be meaningless to you. It will become second nature to you.
button.center is a shortcut for button.frame.center, and is the coordinate of the center of the button inside the superview's coordinate system.
button.height is a shortcut for button.frame.size.height
Here are the basic rules (so you predict what happens). a view's positionis defined by its top left point, and a width and height. If you change width or height, the top left corner stays put.
(there is not really a way to say, i want to position using the center, or bottom left, etc, so the convention is, top left)
Now, if you want to expand about the center, one approach is to simply store the center location and set it back again
oldcenter=btn.center btn.width=150 btn.center=oldcenter
Another thing that confuses most people is the difference between frame and bounds. It toom me a long time to understand... frame refers to your position in your parent's coordinate system (i.e relative to your superview's top left corner). bounds refers to your position in your OWN coordinate system. So, if you want to center a button inside another view, you use
view.add_subview(btn) btn.center = view.bounds.center
(btn.center refers to btn.frame.center, so is in the super view coordsys, and in this case we want it to match the superview center).
Now, if you want to KEEP the centers aligned when the screen rotates, you would use flex, which is how you tell the system whether you intended to place your button really at a particular pixel value, or are more interested in the relative relationship.
adjusting bounds also becomes important when you start dealing with ui.Transforms.
Thanks for the replies. It is becoming much clearer.