0

So I am new to Kivy and Gui coding in general.... I am trying to have a moveable image, and here is the code I have so far tried:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.image import Image
from kivy.uix.behaviors import DragBehavior
from kivy.uix.floatlayout import FloatLayout 

class Box_layout(FloatLayout):
    def __init__(self,**kwargs):
        super(Box_layout, self).__init__(**kwargs)
        self.size_hint = (.50,.50)
        self.orientation = "vertical"
        self.add_widget(MoveableImage())#drag_rectangle = [self.x, self.y, self.width, self.height],source="temp_plot.png"))


class MoveableImage(DragBehavior,Image):

    def __init__(self, **kwargs):
        super(MoveableImage, self).__init__(**kwargs)
        self.drag_timeout = 10000000
        self.drag_distance = 0
        #self.drag = DragBehavior()
        #self.drag.drag_rectangle = [self.x, self.y, self.width, self.height]

        
class gameApp(App):
    def build(self):
        wimg = MoveableImage(source="temp_plot.png")
        m = Box_layout()



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

What happens is I currently have a blank 'image' that is draggable on the first click, but then reaches a timeout or something where it cannot be moved after it has been moved once..... I figured it was a timeout issue or something though self.drag_timeout = 10000000 did not fix the issue...what am I doing wrong here? Further, when I am passing an actual source to MoveableImage, ie self.add_widget(MoveableImage(source='tmp.png')), the image never is moveable to begin with, which again is very confusing to me....if someone could help and explain what is going on and then explain why these behaviors are occurring, hat would be awesome!

Connor
  • 53
  • 1
  • 7

1 Answers1

2

You also need to keep the drag_rectangle of the MoveableImage updated. The easiest way to do that is by using the kv language. So your MoveableImage class can be simply:

class MoveableImage(DragBehavior, Image):
    pass

Then load a kv rule like this:

kv = '''
<MoveableImage>:
    # Define the properties for the MoveableImage
    drag_rectangle: self.x, self.y, self.width, self.height
    drag_timeout: 10000000
    drag_distance: 0
'''
Builder.load_string(kv)

The advantage of using kv here is that it automatically sets up bindings that you would otherwise have to code up yourself. The drag_rectangle is an example of that, so when the MoveableImage is moved (dragged), the drag_rectangle is automatically updated.

If you want to set up those bindings yourself (and not use kv), yu can define your MoveableImage as:

class MoveableImage(DragBehavior, Image):

    def __init__(self, **kwargs):
        super(MoveableImage, self).__init__(**kwargs)
        self.drag_timeout = 10000000
        self.drag_distance = 0
        self.drag_rectangle = [self.x, self.y, self.width, self.height]

    def on_pos(self, *args):
        self.drag_rectangle = [self.x, self.y, self.width, self.height]

    def on_size(self, *args):
        self.drag_rectangle = [self.x, self.y, self.width, self.height]
John Anderson
  • 35,991
  • 4
  • 13
  • 36
  • Thanks for this....I have seen similar things done this way, notably in the Kivy documentation....though for the purposes of actually learning the interaction of all the Kivy classes, if you could show how this would be done in a 'normal' programming way, that would really help for my understanding... – Connor Aug 27 '20 at 14:32
  • What I also don't understand, I thought I tried an equivalent to what you wrote there, regarding the maintaining of the drag_rectangle, with this 'self.drag.drag_rectangle = [self.x, self.y, self.width, self.height]'....that also did not do what I wanted...Do you know why that is? Sorry for these simple questions – Connor Aug 27 '20 at 14:34
  • 1
    My original answer is the is the 'normal' programming way for python/kivy. But I have updated my answer to show how to do it without `kv`. Note that the `self.drag_rectangle = [self.x, self.y, self.width, self.height]` in the `__init__()` method sets the `drag_rectangle` according to the size and position of the `MovebleImage` when the `__init__()` method is executed, but at that point size is `[100,100]` and position is `[0,0]` (the defaults). And that line in `__init__()` does not set up any binding, so those values for `drag_rectangle` will not be adjusted. – John Anderson Aug 27 '20 at 18:03
  • Thanks for the clarification...though I guess my confusion is coming from the 'binding' you mention....what is calling those functions on_pos and on_size, or otherwise triggering them to execute? – Connor Aug 27 '20 at 19:23
  • 1
    Any `on_property()` methods of class are automatically called by the `EventDispatcher` base of all `Widgets` whenever the `property` changes. See the [Properties Documentation](https://kivy.org/doc/stable/api-kivy.properties.html#observe-using-on-propname). Another way to do it is by using `bind` as described in the [Widget Documentation](https://kivy.org/doc/stable/api-kivy.uix.widget.html#using-properties). – John Anderson Aug 27 '20 at 20:08