Welcome!
This is the community forum for my apps Pythonista and Editorial.
For individual support questions, you can also send an email. If you have a very short question or just want to say hello — I'm @olemoritz on Twitter.
Changing button shape using up.Path
-
I want to have a button that has a different shape than a rectangle. I think ui.Path is the way to go but I am having trouble implementing it. I have code for a simple button press. Could I get some help changing it so the button changes to say a hexagon?
import ui # Define variables btn_counter=-1 # button pressed count btn_color=['red','magenta','blue','green','yellow','cyan'] # button colours btn_txt=['click again','click one more time','have another go','go again please', 'one last press','finally'] # button text when pressed # Define functions # What button1 does when tapped def button1_tapped(sender): global btn_counter # count number of times the button is pressed btn_counter+=1 if btn_counter<=5: # cycle through button colours sender.title = btn_txt[btn_counter] # change button text when pressed sender.size_to_fit() # adjust button size to fit new text exactly button1.width=1.5*button1.width # change button width button1.height=2*button1.height # change button height button1.bg_color = btn_color[btn_counter] # change button colour when tapped else: view.remove_subview(button1) # remove button some_box.title = 'thank you for your time' # change box text some_box.size_to_fit() # change box size to fit new text exactly some_box.frame=(view.width*0.38,view.height*0.45,1.1*some_box.width,2*some_box.height) # change box location and size # Create display, further details see theBackground.py view=ui.View() view.present('fullscreen', hide_title_bar=True) view.background_color = (214/255,12/255,140/255) # Create button button1 = ui.Button(title='Click me') # initial button text button1.center = (view.width*0.38, view.height*0.45) # Button initial position button1.border_width = 5 # give button a border #button1.size_to_fit() # fit button around text exactly button1.width = view.width*0.3 # button width button1.height = view.height*0.2 # button height button1.bg_color = (.3,.31,.32) # button colour (.3,.31,.32,0) fof transparent button1.font = ('Chalkduster', 30) # button font type and size button1.tint_color=(1,1,1) # button font colour button1.action = button1_tapped # needed for when button pressed view.add_subview(button1) # display button # Include non-interactive box some_box = ui.Label( text='This is not a button', # box text background_color=(95/255,96/255,98/255), # box colour text_color='white', # box text colour alignment=ui.ALIGN_CENTER, # text alignment in box number_of_lines=0, # number of lines used in box frame=(10, 10, view.width-20, 100)) # box position (10 in, 10 down, view.width-20 wide, 100 high) some_box.font=('HoeflerText-BlackItalic', 40) # box font type and size view.add_subview(some_box) # show box
-
Try changing the draw method in this example.
-
-
import ui, math # Define variables btn_counter=-1 # button pressed count btn_color=['red','magenta','blue','green','yellow','cyan'] # button colours btn_txt=['click again','click one more time','have another go','go again please', 'one last press','finally'] # button text when pressed def make_polygon(num_sides, x=0, y=0, radius=100, phase=0, line_width=5): path = ui.Path() path.move_to(x,y) path.line_width = line_width for i in range(num_sides): t = 2*math.pi*i/num_sides x1, y1 = radius+radius*math.cos(t+phase), radius+radius*math.sin(t+phase) if i: path.line_to(x+x1, y+y1) else: path.move_to(x+x1,y+y1) path.close() return path def create_image(w, h, bg, fg): img = None with ui.ImageContext(w, h) as ctx: ui.set_color(bg) rect = ui.Path.rect(0,0,w,h) rect.fill() ui.set_color(fg) path = make_polygon(6, 0, 0, h/2, math.pi/2) path.fill() img = ctx.get_image() return img # Define functions # What button1 does when tapped def button1_tapped(sender): global btn_counter # count number of times the button is pressed btn_counter+=1 if btn_counter<=5: # cycle through button colours sender.title = btn_txt[btn_counter] # change button text when pressed sender.size_to_fit() # adjust button size to fit new text exactly button1.width=button1.width # change button width button1.height=button1.width # change button height main_bg = (214/255,12/255,140/255) button1.background_image = create_image(button1.width, button1.height, main_bg, btn_color[btn_counter]) #button1.bg_color = btn_color[btn_counter] # change button colour when tapped else: view.remove_subview(button1) # remove button some_box.title = 'thank you for your time' # change box text some_box.size_to_fit() # change box size to fit new text exactly some_box.frame=(view.width*0.38,view.height*0.45,1.1*some_box.width,2*some_box.height) # change box location and size # Create display, further details see theBackground.py view=ui.View() view.present('fullscreen') view.background_color = (214/255,12/255,140/255) # Create button button1 = ui.Button(title='Click me') # initial button text button1.center = (view.width*0.38, view.height*0.45) # Button initial position #button1.border_width = 5 # give button a border #button1.size_to_fit() # fit button around text exactly button1.width = view.width*0.3 # button width button1.height = view.height*0.2 # button height button1.bg_color = (.3,.31,.32) # button colour (.3,.31,.32,0) fof transparent button1.font = ('Chalkduster', 30) # button font type and size button1.tint_color=(1,1,1) # button font colour button1.action = button1_tapped # needed for when button pressed view.add_subview(button1) # display button # Include non-interactive box some_box = ui.Label( text='This is not a button', # box text background_color=(95/255,96/255,98/255), # box colour text_color='white', # box text colour alignment=ui.ALIGN_CENTER, # text alignment in box number_of_lines=0, # number of lines used in box frame=(10, 10, view.width-20, 100)) # box position (10 in, 10 down, view.width-20 wide, 100 high) some_box.font=('HoeflerText-BlackItalic', 40) # box font type and size view.add_subview(some_box) # show box
-
@brumm thanks for the help but the code In the link did not work when I tried to run it.
@enceladus this is a start but the button still exists as a rectangle around the hexagon picture. Any tips to make sure that only tapping the shape will activate the button?
-
Need to write "inside" function.
# coding: utf-8 import ui, math class MyButtonClass(ui.View): def __init__(self): self.color = 'red' #touch event are limited to this area (left=100,top=100,right=200,bottom=200) self.x = 100 self.y = 100 self.height = 100 self.width = 100 self.main_bg = 'black' self.fg = 'red' def make_polygon(self, num_sides, x=0, y=0, radius=100, phase=0, line_width=5): path = ui.Path() path.move_to(x,y) path.line_width = line_width for i in range(num_sides): t = 2*math.pi*i/num_sides x1, y1 = radius+radius*math.cos(t+phase), radius+radius*math.sin(t+phase) if i: path.line_to(x+x1, y+y1) else: path.move_to(x+x1,y+y1) path.close() return path def draw(self): w, h = self.width, self.height ui.set_color(self.main_bg) rect = ui.Path.rect(0,0,w,h) rect.fill() ui.set_color(self.fg) path = self.make_polygon(6, 0, 0, h/2, math.pi/2) path.fill() def inside(self, touch): return True def touch_ended(self, touch): if not self.inside(touch): return if self.fg == 'red': self.fg = 'blue' else: self.fg = 'red' self.set_needs_display() class SpecialButton(object): def __init__(self): self.view = ui.View() self.view.present('fullscreen') self.btn = MyButtonClass() self.view.add_subview(self.btn) SpecialButton()
-
Perhaps, inside(touch) could check the color of touch.location?
-
Here is an implementation. Not tested well. (Used Brumm code)
# coding: utf-8 from matplotlib import path import ui, math class MyButtonClass(ui.View): def __init__(self): self.color = 'red' #touch event are limited to this area (left=100,top=100,right=200,bottom=200) self.x = 100 self.y = 100 self.height = 100 self.width = 100 self.main_bg = 'black' self.fg = 'red' self.points = [] def make_polygon(self, num_sides, x=0, y=0, radius=100, phase=0, line_width=5): path1 = ui.Path() path1.move_to(x,y) path1.line_width = line_width points = [] for i in range(num_sides): t = 2*math.pi*i/num_sides x1, y1 = radius+radius*math.cos(t+phase), radius+radius*math.sin(t+phase) points.append((x+x1, y+y1)) if i: path1.line_to(x+x1, y+y1) else: path1.move_to(x+x1,y+y1) path1.close() return (path1, points) def draw(self): w, h = self.width, self.height ui.set_color(self.main_bg) rect = ui.Path.rect(0,0,w,h) rect.fill() ui.set_color(self.fg) path1, self.points = self.make_polygon(6, 0, 0, h/2, math.pi/2) path1.fill() def inside(self, touch): p = path.Path(self.points) return p.contains_points([touch.location])[0] def touch_ended(self, touch): if not self.inside(touch): return if self.fg == 'red': self.fg = 'blue' else: self.fg = 'red' self.set_needs_display() class SpecialButton(object): def __init__(self): self.view = ui.View() self.view.present('fullscreen') self.btn = MyButtonClass() self.view.add_subview(self.btn) SpecialButton()
-
@enceladus That last code worked, just a quick question, if I wanted a second button, is there an easy way to do that?
-
class MyButtonClass(ui.View): def __init__(self, x, y, height, width): self.x = x self.y = y self.height = height self.width = width class SpecialButton(object): def __init__(self): self.view = ui.View() self.view.present('fullscreen') self.btn = MyButtonClass(100, 100, 100, 100) self.btn2 = MyButtonClass(200, 100, 100, 100) self.view.add_subview(self.btn) self.view.add_subview(self.btn2)
-
@brumm thanks, just enough info for me to figure it out.