Search code examples
kivyz-index

KIVY zindex dynamic change


I am trying to add 4 boxes in Relativelayout. Able to horizontally move only the box which gets added last in relativelayout. All other box gets strucked up when it is moved closer to its box which got added later. In given sample code below 'Actor 400' freely moves horizontally across the scene. 'Actor 300' able to move freely over 'Actor 200' and 'Actor 100'. But when I try to move Actor 300 above Actor 400, it get strucked and only after mouse moves beyond Actor 400, I am able to move.

Can I change the zindex of the widget dynamically when I touch it.

from kivy.app import App
from kivy.graphics import Line, Color
from kivy.uix.scatter import Scatter
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.lang import Builder

KV = '''
<Actor>:
    canvas:
        Color:
            rgba: 0,1,0,.8
        Rectangle:
            id: _rect_
            size: 100, 30
            pos: 0, root.height - 30
        Line:
            points: 50, root.height - 30, 50, 20
            width:2
    Label:
        id: _actr_lbl
        text: 'Hello World'
        color: 0,0,0,1
        size_hint: None, None
        size: 100, 30
        pos: 0, root.height - 30
'''


Builder.load_string(KV)
class Actor(Scatter):
    def __init__(self, **kwargs) :
        Name = kwargs.pop('Name', 'Actor-NoName')
        super(Actor, self).__init__(**kwargs)
        self.Name = Name
        self.ids._actr_lbl.text = Name

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
           self.selected = True
           self.pos_hint = {'top':1}
           self.hint_diff_touch_to_x = self.right - touch.x
           return True
        return super(Actor, self).on_touch_down(touch)

    def on_touch_move(self, touch):
        if (self.selected) :
            future_right = touch.x +  self.hint_diff_touch_to_x
            if (future_right <= self.parent.size[0]) and ((future_right - self.width) >= 0) :
               self.right = future_right
               self.pos_hint = {'top':1}
               return True
        return super(Actor, self).on_touch_move(touch)

    def on_touch_up(self, touch):
        if (self.selected) :
            self.selected = False
            self.hint_diff_touch_to_x = 0
            self.iy = 0
            return True
        return super(Actor, self).on_touch_up(touch)

class MyPaintApp(App):

    def build(self):
        root = RelativeLayout()

        (ix, iy) = (100,100)

        clr = Color(0.2, 0.2, 1)

        for ix in [100, 200, 300, 400 ] :
            root.add_widget(Actor(Name = 'Actor ' + str(ix), pos=(ix,0), size_hint=(None,1)))

        return root

if __name__ == '__main__':
    Window.clearcolor = (1, 1, 1, 1)
    MyPaintApp().run()

Solution

  • When one of your Actor Widgets is selected, you can move it to the top by removing it and re-adding it, like this:

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
           self.selected = True
           self.pos_hint = {'top':1}
           self.hint_diff_touch_to_x = self.right - touch.x
           parent = self.parent
    
           # move this Actor to the front
           parent.remove_widget(self)
           parent.add_widget(self)
    
           return True
        return super(Actor, self).on_touch_down(touch)