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.
how to draw a sketch into an image (not fullscreen)?[SOLVED]
-
Starting from @omz sketch example, i have modified it (see below) to:
- have a smaller view.
- not start in 0,0.
My goal is to have several distinct areas on the screen where i can draw into, not just 1big area.
# SketchView # this class provides a container for hand drawing import ui # The PathView class is responsible for tracking # touches and drawing the current stroke. # It is used by SketchView. class PathView (ui.View): def __init__(self, frame): self.frame = frame self.path = None def touch_began(self, touch): x, y = touch.location self.path = ui.Path() self.path.line_width = 8 self.path.line_join_style = ui.LINE_JOIN_ROUND self.path.line_cap_style = ui.LINE_CAP_ROUND self.path.move_to(x, y) def touch_moved(self, touch): x, y = touch.location self.path.line_to(x, y) self.set_needs_display() def touch_ended(self, touch): # Send the current path to the SketchView: if callable(self.onTouchEnded): self.onTouchEnded(self) # Clear the view (the path has now been rendered # into the SketchView's image view): self.path = None def draw(self): if self.path: self.path.stroke() class SketchView (ui.View): def __init__(self, frame, background_color='white'): self.background_color = background_color self.frame = frame # the image manager iv = ui.ImageView(frame=self.bounds) self.image_view = iv self.add_subview(iv) # the path manager pv = PathView(frame=self.bounds) pv.onTouchEnded = self.savePathToImage self.add_subview(pv) def savePathToImage(self, sender): path = sender.path old_img = self.image_view.image width, height = self.image_view.width, self.image_view.height with ui.ImageContext(width, height) as ctx: if old_img: old_img.draw() path.stroke() self.image_view.image = ctx.get_image() # you must have a global view to embed the sketch views gv = ui.View(background_color='white') gv.present('fullscreen') # now creat 1 sketch view sv = SketchView(frame=(100,100,512,512), background_color='pink') gv.add_subview(sv) # and a second one sv2 = SketchView(frame=(700, 100, 300, 300), background_color='cyan') gv.add_subview(sv2)
-
Inside of
SketchView.__init__()
you might want to addprint(self.bounds, self.frame)
to ensure that you are consistently using the right one. If you change topv = PathView(frame=self.frame) # was self.bounds
that solves some of your issues.My sense is that
ui.Path.add_clip()
is the way to get rid of out-of-bounds drawing but graphics is not my thing so I might have this wrong. -
@ccc thanks for your answer.
I have started getting things better with bounds and frame, but still some pb i dont understand. I have to study carefully these properties before using them.
Path.add_clip i tried but didnt work.I'll come back with a solution some day, unless someone solves it for me first.
-
Touch.moved continues to fire even if outside the bounds of the original view.
So, you need to check whether the current x,y is in bounds before adding to the path.def hit(self,location): if location[0]<0 or location[1]<0 or location[0]>self.width or location[1]>self.height: return False else : return True def touch_moved(self, touch): if self.hit(touch.location): # do stuff
Note if you leave the view, then come around to the other side, you might get an undesirable jump. One option would be to have a
drawing
flag which gets set to false when moving out of bounds ortouch_end
, then rearmed during touchbegan, or when reentering the bounds. Then, if touchmoved is called and drawing is false, you would use move_to instead of line_to -
@JonB thanks.
'bounds' can be tricky. Here is some of my results below, now i start to understand why it did not work as expected.
I have learned 3 things not in the doc:- [1] calling present(fullscreen) changes frame to (0, 64, displayWidth, displayHeight-64)
- [2] it seems that changing the bounds width & height keeps the center of the frame unchanged, so frame x,y is changed.
- [3] changing bounds x,y seems to have no action on frame x,y. But bound x,y has the new value, incoherent with frame x,y...
These facts are important to know.
import ui import console # Some experiments with View, frame, bounds # lets create a top view: v0 = ui.View() v0.background_color = 'white' v0.border_color = 'gray' v0.border_width = 5 v0.corner_radius = 20 v0.frame = (100,100,300,300) console.clear() print('frame={0} bounds={1}').format(v0.frame, v0.bounds) # frame=(100.0, 100.0, 300.0, 300.0) bounds=(0.0, 0.0, 300.0, 300.0) # this is ok, but now: v0.present('fullscreen') print('frame={0} bounds={1}').format(v0.frame, v0.bounds) # frame=(0.0, 64.0, 1024.0, 704.0) bounds=(0.0, 0.0, 1024.0, 704.0) :ref [1] # calling present changes v0.frame to (0, 64, displayWidth, displayHeight-64) # now lets create some child view v1 = ui.View( frame = (100,100,300,300), background_color = 'white') v1.border_color = 'pink' v1.border_width = 3 v1.corner_radius = 10 v2 = ui.View() v2.frame = (10,10,100,100) v2.background_color = 'pink' v2.border_color = 'blue' v2.border_width = 4 v2.corner_radius = 1 v1.add_subview(v2) v0.add_subview(v1) print('frame={0} bounds={1}').format(v2.frame, v2.bounds) # frame=(10.0, 10.0, 100.0, 100.0) bounds=(0.0, 0.0, 100.0, 100.0) # this is ok v2.bounds=(0, 0, 200, 200) print('frame={0} bounds={1}').format(v2.frame, v2.bounds) # frame=(-40.0, -40.0, 200.0, 200.0) bounds=(0.0, 0.0, 200.0, 200.0) : ref [2] # this was not expected! why is the frame x,y = -40,-40 now? # it seems that changing the bounds width & height keeps the center of the view unchanged v2.bounds=(0, 0, 100, 100) print('frame={0} bounds={1}').format(v2.frame, v2.bounds) # frame=(10.0, 10.0, 100.0, 100.0) bounds=(0.0, 0.0, 100.0, 100.0) # ok we are back in place v2.bounds=(50, 50, 100, 100) print('frame={0} bounds={1}').format(v2.frame, v2.bounds) # frame=(10.0, 10.0, 100.0, 100.0) bounds=(50.0, 50.0, 100.0, 100.0) : ref [3] # changing bounds x,y seems to have no action on frame x,y... why?
-
@JonB i probably dont need to check the bounds. If the path is included in the good subview, it wont get touch events that are outside the subview. The whole thing is to master what are exactly the subview coordinates... But i am getting close...
-
SOLVED.
I have modified the 1rst post code to show the solution. thanks everyone for your help.