嵌套的窗口小部件的画布不会绘制任何东西

时间:2014-08-25 14:47:42

标签: python canvas kivy

我有两个三个嵌套的小部件来处理on_touch_down事件,点击第一个父级,事件被感知到第二个,然后是第三个。通过这次点击,第三个小部件应该在它的画布上绘制,但这不会发生。

我理解画布对象及其组的动态。所以我真的不明白为什么会发生这种情况

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

这是我的一段代码,展示了如何链接类。 Spline_guide没有绘制任何内容。想法?

1 个答案:

答案 0 :(得分:1)

添加到另一个Widget

Widget将在后者Widget的{​​{1}}中绘制。当您致电canvas时(即self.canvas.clear()),您将移除所有儿童画布。

您可以使用Editable_pointcanvas.before代替您的绘图,也可以保存说明并稍后修改:

canvas.after

然后你根本不需要清除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 。这是首选解决方案,因为它提供了最佳性能。