Search code examples
pythonkivykivy-language

Kivy execute function when widget is dragged


I have a little demo here:

From DemoApp.py:

from kivy.app import App
from kivy.uix.button import Button
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.behaviors import DragBehavior
from kivy.core.window import Window


class DraggableButton(DragBehavior, Button):
    def on_drag(self, *args):
        ...


class DemoLayout(FloatLayout):
    def __init__(self, **kwargs):
        super(DemoLayout, self).__init__(**kwargs)
        self.add_widget(DraggableButton(text='Drag Me'))


class DemoApp(App):
    def build(self):
        self.button= DraggableButton(text='Drag Me')
        Window.bind(mouse_pos=lambda w, p: setattr(self.button, "mouse_pos", p))
        return self.button


if __name__ == '__main__':
    DemoApp().run()

From demo.kv:

<DraggableButton>:
    drag_rectangle: self.x, self.y, self.width, self.height
    drag_timeout: 10000000
    drag_distance: 0

The problem is, I want to call my on_drag method when the DraggableButton is dragged.

Also, I only want the mouse position while in the function, so I can remove the line
Window.bind(mouse_pos=lambda w, p: setattr(self.button, "mouse_pos", p))

Is there any solution to this?


Solution

  • It uses DragBehavior so I found source code for DragBehavior
    and I see it has method on_touch_move(touch).

    I replaced this method in DraggableButton() and when button is moved then it gets MouseMotionEvent with pos which seems to be mouse position.

    from kivy.app import App
    from kivy.uix.button import Button
    from kivy.uix.floatlayout import FloatLayout
    from kivy.uix.behaviors import DragBehavior
    from kivy.core.window import Window
    
    
    class DraggableButton(DragBehavior, Button):
        def on_touch_move(self, touch):  
            super().on_touch_move(touch)  # run original `on_touch_move()`
            
            print('[on_drag] touch:', touch)
            
            #print('[on_drag] touch.dpos:', touch.dpos)
            #print('[on_drag] touch.spos:', touch.spos)
            print('[on_drag] touch.pos:', touch.pos)
    
            print('---')
    
    
    class DemoApp(App):
        def build(self):
            self.button = DraggableButton(text='Drag Me')
            return self.button
    
    
    if __name__ == '__main__':
        DemoApp().run()
    

    Result:

    [on_drag] touch: <MouseMotionEvent spos=(0.36, 0.5766666666666667) pos=(288.0, 346.0)>
    [on_drag] touch.pos: (288.0, 346.0)
    ---
    [on_drag] touch: <MouseMotionEvent spos=(0.35875, 0.5783333333333334) pos=(287.0, 347.0)>
    [on_drag] touch.pos: (287.0, 347.0)
    ---
    [on_drag] touch: <MouseMotionEvent spos=(0.35875, 0.5783333333333334) pos=(287.0, 347.0)>
    [on_drag] touch.pos: (287.0, 347.0)
    ---