Boundary box for draggable widget

44 views
Skip to first unread message

maseec

unread,
Nov 16, 2017, 2:44:00 AM11/16/17
to kivy-...@googlegroups.com
Hi there,

I have a (very) simple widget that can be dragged around by the user. Now, is it easily possible to define an area that contains this widget (ideally another widget) and where the draggable element cannot be dragged outside?
I looked at the code of DragBehavior (which is a parent for the draggable widget), but I do not see a chance to implement this behavior by overriding a method. My current solution is a bit clunky, I have a copy of the entire code of DragBehavior and changed just two lines in on_touch_move (lines 188 and 189 here: https://github.com/kivy/kivy/blob/master/kivy/uix/behaviors/drag.py) to

self.center_x = max(min(self.center_x + touch.dx, self.bounds_rect_x + self.bounds_rect_width - 1), self.parent.x + 1)
self.center_y = max(min(self.center_y + touch.dy, self.bounds_rect_y + self.bounds_rect_height - 1), self.parent.y + 1)

Additionally, I defined 5 properties for a bounds_rectange, just like the ones for the drag_rectangle.
I do not see a way to override on_touch_move, as apart from the two changed lines the code is the same, but the changed lines should not be executed (right?)

Does anybody see a more elegant solution?

Regards
maseec

ZenCODE

unread,
Nov 16, 2017, 3:54:02 PM11/16/17
to kivy-...@googlegroups.com
Why "an entire copy"? Try sub-classing. It's much cleaner and correct, as you should never really alter the behavior of previously defined classes. If you want new behavior, you need a new class (or a class factory with parameters)....

Message has been deleted

maseec

unread,
Nov 16, 2017, 6:39:16 PM11/16/17
to Kivy users support
Have you read my post? I wrote that i don't see a chance to implement this behavior. Can you please send a quick suggestion how i can achieve this by subclassing?
Message has been deleted

ZenCODE

unread,
Nov 16, 2017, 10:40:33 PM11/16/17
to Kivy users support
Sorry, I am often guilty of rushing. This does should do what you want no?

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.lang import Builder
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import DragBehavior

Builder.load_string('''
<DraggableFloat>:
size_hint: (0.1, 0.1)
canvas:
Color:
rgba: [1, 0, 0, 0.5] if root.selected else [0, 0, 1, 0.5]
Rectangle:
pos: self.pos
size: self.size
''')


class DraggableFloat(DragBehavior, FloatLayout):
selected = BooleanProperty(False)

def on_touch_down(self, touch):
if self.collide_point(*touch.pos):
self.selected = True
return super(DraggableFloat, self).on_touch_down(touch)

def on_touch_up(self, touch):
self.selected = False
return super(DraggableFloat, self).on_touch_up(touch)


class TestApp(App):
def build(self):
container = FloatLayout()
container.add_widget(DraggableFloat())
return container


if __name__ == "__main__":
TestApp().run()
Reply all
Reply to author
Forward
0 new messages