amit yakovian
amit yakovian

Reputation: 91

Kivy get the object that was pressed on

I have a Kivy app that has a scrollview within it. In this scrollview there's a boxlayout that holds a pretty big amount of images and it changes throughout runtime (it can go from 1 to 300 at any time). When a touchdown event happens, I need to know on which image the user has pressed (meaning which on they were "on" at the moment, as they can scroll up and down), and maybe even get the coordinates of the press relative to the image and not the whole screen (I need to draw on the place they pressed and I cannot do it without knowing which image they pressed on and where). How can I do that?

That's how it's defined in the kv file:


            MyScrollView:
                bar_color: [1, 0, 0, 1]
                id: notebook_scroll
                padding: 0
                spacing: 0
                do_scroll: (False, True)  # up and down
                BoxLayout:
                    padding: 0
                    spacing: 0
                    orientation: 'vertical'
                    id: notebook_image
                    size_hint: 1, None
                    height: self.minimum_height
                    MyImage:

<MyImage>:
    source: 'images/notebook1.png'
    allow_stretch: True
    keep_ratio: False
    size: root.get_size_for_notebook()
    size_hint: None, None

It's basically an infinite notebook, and during runtime the python code adds more "MyImage" objects to the boxlayout (which is a photo of a notebook page).

Upvotes: 3

Views: 245

Answers (1)

John Anderson
John Anderson

Reputation: 39012

Try adding this method to your MyImage:

def to_image(self, x, y):
    ''''
    Convert touch coordinates to pixels

     :Parameters:
        `x,y`: touch coordinates in parent coordinate system - as provided by on_touch_down()

     :Returns: `x, y`
         A value of None is returned for coordinates that are outside the Image source
    '''

    # get coordinates of texture in the Canvas
    pos_in_canvas = self.center_x - self.norm_image_size[0] / 2., self.center_y - self.norm_image_size[1] / 2.

    # calculate coordinates of the touch in relation to the texture
    x1 = x - pos_in_canvas[0]
    y1 = y - pos_in_canvas[1]

    # convert to pixels by scaling texture_size/source_image_size
    if x1 < 0 or x1 > self.norm_image_size[0]:
        x2 = None
    else:
        x2 =  self.texture_size[0] * x1/self.norm_image_size[0]
    if y1 < 0 or y1 > self.norm_image_size[1]:
        y2 = None
    else:
        y2 =  self.texture_size[1] * y1/self.norm_image_size[1]
    return x2, y2

Then you can add an on_touch_down() to your MyImage class:

def on_touch_down(self, touch):
    if self.collide_point(*touch.pos):
        print('got a touch on', self, 'at', touch.pos, ', at image pixels:', self.to_image(*touch.pos))
        return True
    else:
        return super(MyImage, self).on_touch_down(touch)

Upvotes: 3

Related Questions