Reputation: 148
I've got two three nested widget which handle the on_touch_down event, clicking on the first parent, the event is sensed to the second and then the third. With this click the third widget should draw on it's canvas but this it's not happening.
I understand the dynamic of the canvas object and it's groups. So I don't really understand why this is happening
class Spline_guide(DragBehavior, Button):
def __init__(self, **kw):
super(Spline_guide, self).__init__(**kw)
self.bind(pos = self.update_spline , size = self.update_spline)
def update_spline(self, *l):
self.pos = self.parent.pos
return self
def show_spline(self,*l):
print 'show spline'
with self.canvas:
Color(0,1,0)
######## THIS ISTRUCTION DOESN'T WORK
Ellipse(pos = (100,100), size = (100,100))
return self
def hide_spline(self, *l):
print 'hide spline'
self.canvas.clear()
return self
class Editable_point(DragBehavior, Widget):
def __init__(self, name,x,y, **kw):
super(Editable_point, self).__init__(**kw)
self.drag_rectangle = (0,0 ,800,300)
self.drag_timeout = 10000000
self.drag_distance = 0
self.name = name
self.pos = (x - DOT_DIMENSION / 2,y - DOT_DIMENSION / 2)
self.size = (DOT_DIMENSION, DOT_DIMENSION)
self.spline = Spline_guide()
self.add_widget(self.spline)
self.SHOW_SPLINE = False
self.bind(pos = self.check_pos)
def check_pos(self, *l):
self.area = self.parent.parent
self.x = self.x if self.x > self.area.x else self.area.x
self.y = self.y if self.y > self.area.y else self.area.y
return self
def draw_point(self):
self.area = self.parent.parent
self.drag_rectangle = (self.area.x, self.area.y, self.area.width, self.area.height)
self.canvas.clear()
with self.canvas:
Color(1,0,0)
Ellipse(pos=self.pos, size=self.size)
return self
def on_enter(self, pop):
def wrap(l):
if l.text in ['start','stop']:
print 'you can not use start or stop as name'
pop.dismiss()
return wrap
if self.name in ['start','stop']:
pop.dismiss()
print 'you can not edit the name of start or stop point'
return wrap
self.name = l.text
pop.dismiss()
return wrap
def show_info(self, *l):
graph = self.parent.parent.graph
X_OFFSET = graph._plot_area.x + self.parent.x - DOT_DIMENSION / 2
Y_OFFSET = graph._plot_area.y + self.parent.y - DOT_DIMENSION / 2
_x = self.x - X_OFFSET
_y = self.y - Y_OFFSET
x, y = normalize(graph.xmin,graph.ymin,graph.xmax,graph.ymax,graph._plot_area.width,graph._plot_area.height, _x, _y)
point_name = TextInput(text=self.name, multiline = False)
point_info = Popup(title ="X: {} Y: {}".format(x,y), content = point_name, size_hint=(None,None), size=(200,100))
point_name.bind(on_text_validate=self.on_enter(point_info))
point_info.open()
return self
def on_touch_down(self, *l):
if self.SHOW_SPLINE:
self.SHOW_SPLINE = False
self.spline.hide_spline()
else:
self.SHOW_SPLINE = True
self.spline.show_spline()
return self
class Editable_line(Widget):
def __init__(self, **kw):
super(Editable_line, self).__init__(**kw)
self._old_ = [100,100]
self.old_pos = [0,0]
self.bind(pos=self.update_line, size=self.update_line)
def replace_start_stop(self, new_elem):
elem = filter(lambda x: x.name == new_elem.name, [ i for i in self.children if hasattr(i,'name')])
if elem: self.remove_widget(elem[0])
self.add_widget(new_elem)
return self
def update_points(self):
r_x = float(Window.size[0]) / float(self._old_[0])
r_y = float(Window.size[1]) / float(self._old_[1])
for p in [ i for i in self.children if hasattr(i,'name')]:
new_x = p.x * r_x
new_y = p.y * r_y
p.x = new_x
p.y = new_y
p.size = (DOT_DIMENSION, DOT_DIMENSION)
return self
def update_line(self, *a):
self.pos = self.parent.pos
self.size = self.parent.size
self.parent.graph.pos = self.pos
self.parent.graph.size = self.size
self.parent.graph._redraw_size()
#Coordinate per start e stop personalizzare sul graph
y = self.parent.graph._plot_area.y + self.y
x = self.parent.graph._plot_area.x + self.x
h = self.parent.graph._plot_area.height
w = self.parent.graph._plot_area.width
self.replace_start_stop(Editable_point('start', x, y + h / 2))
self.replace_start_stop(Editable_point('stop', x + w, y + h / 2))
self.update_points()
self._old_ = Window.size
return self.draw_line()
def sort_points(self):
self.children = sorted(self.children , key=attrgetter('x'))
return self
def control_presence(self,coordinates):
x = int(coordinates.x)
y = int(coordinates.y)
x_range = range(x-DOT_DIMENSION, x+DOT_DIMENSION)
y_range = range(y-DOT_DIMENSION, y+DOT_DIMENSION)
for p in [ i for i in self.children if hasattr(i,'name')]:
if int(p.x) in x_range and int(p.y) in y_range: return p
return False
def on_touch_down(self,coordinates):
#add points
p = self.control_presence(coordinates)
if p:
if not coordinates.is_double_tap:
return p.on_touch_down(coordinates)
return p.show_info(coordinates)
x = int(coordinates.x)
y = int(coordinates.y)
p = Editable_point('new point', x, y)
p.size = (DOT_DIMENSION, DOT_DIMENSION)
self.add_widget(p)
return self.draw_line()
def remove_point(self,coordinates):
p = self.control_presence(coordinates)
if p:
if p.name in ['start','stop']: print 'you can\'t delete start or stop point' else: self.remove_widget(p)
return self.draw_line()
def draw_line(self):
self.sort_points()
self.canvas.before.clear()
_l = list()
for p in [ i for i in self.children if hasattr(i,'name')]:
_l.append(p.x + DOT_DIMENSION/2)
_l.append(p.y + DOT_DIMENSION/2)
p.draw_point()
with self.canvas.before:
Color(0,0.8,1)
Line(points=_l, witdth = LINE_WIDTH)
return self
def on_touch_move(self, coordinates):
p = self.control_presence(coordinates)
if p:
if p.name in ['start','stop']:
return self.parent.on_touch_up(coordinates)
p.on_touch_move(coordinates)
self.draw_line()
return self
This is a piece of my code and show how the classes are linked. The Spline_guide doesn't draw anything. Ideas?
Upvotes: 0
Views: 107
Reputation: 14834
Widget
s which are added to another Widget
are drawn in the latter Widget
's canvas
. When you call self.canvas.clear()
(i.e. in Editable_point
) you are removing all the child canvases.
You could use canvas.before
or canvas.after
for your drawing instead, or you can save the instructions and modify them later:
def __init__(self, **kwargs):
...
with self.canvas:
self.draw_color = Color(0, 1, 0, 1)
self.draw_ellipse = Ellipse(pos=self.pos, size=self.size)
def draw_point(self):
...
self.draw_ellipse.pos = self.pos
self.draw_ellipse.size = self.size
Then you never need to clear the canvas
at all. This is the preferred solution as it offers the best performance.
Upvotes: 1