'How kivy touch_move distincts between objects?

i have a code that produces some rings that are made of textinputs. I want to select each ring individually to rotate them around their pole, but they select together in touch_move. i use some parts of the "Pong Game Tutorial " (that is available on: https://kivy.org/doc/stable/tutorials/pong.html) to figure out how touch_move works and select individually, but that does not work either. What is the problem of the code that can not select and move each ring, to then could rotate each of them individually polar? I should mention that in touch_move, I commented the last attempt that was written for rotating polar rings(that is the main purpose).

import math
from kivy.lang import Builder
from kivy.properties import NumericProperty, ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
from kivy.graphics import *
from kivy.core.window import Window
from kivy.uix.textinput import TextInput
from kivy.uix.widget import Widget

kv = '''
<Ring>:
    #size: 50,20
<Ringa>:
    #size: 50,20
<Scat>:
    ring1 : ring_one
    ring2 : ring_two
    Ring:
        id:ring_one

    Ringa:
        id:ring_two

<-RotatableTI>:
    size_hint: None, None
    canvas.before:
        PushMatrix
        Rotate:
            angle: root.angle
            axis: 0,0,1
            origin: self.center

        Color:
            rgba: self.background_color
        BorderImage:
            border: self.border
            pos: self.pos
            size: self.size
            source: self.background_active if self.focus else (self.background_disabled_normal if self.disabled else self.background_normal)
        Color:
            rgba:
                (self.cursor_color
                if self.focus and not self._cursor_blink
                else (0, 0, 0, 0))
        Rectangle:
            pos: self._cursor_visual_pos
            size: root.cursor_width, -self._cursor_visual_height
        Color:
            rgba: self.disabled_foreground_color if self.disabled else (self.hint_text_color if not self.text else self.foreground_color)
    canvas.after:
        PopMatrix

        
'''

Builder.load_string(kv)

class RotatableTI(TextInput):
    angle = NumericProperty(0)
class Ring(Widget):
    def __init__(self,**kwargs):
        super(Ring, self).__init__(**kwargs)
        pi = math.pi
        txsize_x = 70
        txsize_y = 30
        r = 150
        div=20
        for i in range(1, div):
            angle = 360.0 / (div - 1) * i
            p_x = (Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) *3* r / 2) - txsize_x / 2
            p_y = (Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) *3* r / 2) - txsize_y / 2
            self.add_widget(
                RotatableTI(text="hi" + str(i), size=(txsize_x, txsize_y), pos=(p_x, p_y), angle=angle))
class Ringa(Widget):
    def __init__(self,**kwargs):
        super(Ringa, self).__init__(**kwargs)
        pi = math.pi
        txsize_x = 50
        txsize_y = 30
        r = 150
        div=20
        for i in range(1, div):
            angle = 360.0 / (div - 1) * i
            p_x = (Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) * r ) - txsize_x / 2
            p_y = (Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) * r ) - txsize_y / 2
            self.add_widget(
            RotatableTI(text="hi" + str(i), size=(txsize_x, txsize_y), pos=(p_x,p_y),angle=angle))
class Scat(FloatLayout):
    Window.size = (680, 680)
    angle=NumericProperty(0)
    def __init__(self, **kwargs):
        super(Scat, self).__init__(**kwargs)
        ring1=ObjectProperty(None)
        ring2=ObjectProperty(None)

    def on_touch_move(self, touch):
        if touch.x < self.width / 3:
            print(self.ring1.center_y)
            self.ring1.center_y = touch.y
        if touch.x > self.width - self.width / 3:
            self.ring2.center_y = touch.y
        # y = (touch.y - self.center[1])
        # x = (touch.x - self.center[0])
        # self.tmp = self.angle
        # calc = math.degrees(math.atan2(y, x))
        # self.prev_angle = calc if calc > 0 else 360+calc
        # new_angle = calc if calc > 0 else 360 + calc
        #
        # if self.collide_point(*touch.pos) and 125 ** 2 < (touch.x - self.center[0]) ** 2 + (
        #         touch.y - self.center[1]) ** 2 < 175 ** 2:
        #     self.angle = self.tmp + (new_angle - self.prev_angle) % 360
        #     # print(self.center)
        #     return super(Scat, self).on_touch_move(touch)
        # elif self.collide_point(*touch.pos) and 200 ** 2 < (touch.x - self.center[0]) ** 2 + (
        #         touch.y - self.center[1]) ** 2 < 250 ** 2:
        #     self.angle = self.tmp + (new_angle - self.prev_angle) % 360
        #     return super(Scat, self).on_touch_move(touch)
        # elif self.collide_point(*touch.pos) and 275 ** 2 < (touch.x - self.center[0]) ** 2 + (
        #         touch.y - self.center[1]) ** 2 < 325 ** 2:
        #     self.angle = self.tmp + (new_angle - self.prev_angle) % 360
        #     return super(Scat, self).on_touch_move(touch)
class Mainn(App):
    def build(self):
        return Scat()

if __name__=="__main__":
    Mainn().run()


Solution 1:[1]

Your code, as it stands, does not have the capability to rotate the Ring objects, because there is no code in the Ring classes to do it. You must add an angle property to the Ring classes, as well as canvas instructions to perform the rotation based on that angle and on_touch_move() method to adjust the angle value. Here is a modified version of your code that does that:

import math
from kivy.lang import Builder
from kivy.properties import NumericProperty, ObjectProperty
from kivy.uix.floatlayout import FloatLayout
from kivy.app import App
from kivy.core.window import Window
from kivy.uix.textinput import TextInput
from kivy.uix.widget import Widget

kv = '''
<Ring>:
    #size: 50,20
    canvas.before:
        PushMatrix
        Rotate:
            angle: root.angle
            axis: 0,0,1
            origin: self.center
    canvas.after:
        PopMatrix
<Ringa>:
    #size: 50,20
    canvas.before:
        PushMatrix
        Rotate:
            angle: root.angle
            axis: 0,0,1
            origin: self.center
    canvas.after:
        PopMatrix
<Scat>:
    ring1 : ring_one
    ring2 : ring_two
    Ring:
        id:ring_one

    Ringa:
        id:ring_two

<-RotatableTI>:
    size_hint: None, None
    canvas.before:
        PushMatrix
        Rotate:
            angle: root.angle
            axis: 0,0,1
            origin: self.center

        Color:
            rgba: self.background_color
        BorderImage:
            border: self.border
            pos: self.pos
            size: self.size
            source: self.background_active if self.focus else (self.background_disabled_normal if self.disabled else self.background_normal)
        Color:
            rgba:
                (self.cursor_color
                if self.focus and not self._cursor_blink
                else (0, 0, 0, 0))
        Rectangle:
            pos: self._cursor_visual_pos
            size: root.cursor_width, -self._cursor_visual_height
        Color:
            rgba: self.disabled_foreground_color if self.disabled else (self.hint_text_color if not self.text else self.foreground_color)
    canvas.after:
        PopMatrix


'''

Builder.load_string(kv)


class RotatableTI(TextInput):
    angle = NumericProperty(0)


class Ring(Widget):
    angle = NumericProperty(0)
    def __init__(self, **kwargs):
        super(Ring, self).__init__(**kwargs)
        pi = math.pi
        txsize_x = 70
        txsize_y = 30
        r = 150
        div = 20
        for i in range(1, div):
            angle = 360.0 / (div - 1) * i
            p_x = (Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) * 3 * r / 2) - txsize_x / 2
            p_y = (Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) * 3 * r / 2) - txsize_y / 2
            self.add_widget(
                RotatableTI(text="hi" + str(i), size=(txsize_x, txsize_y), pos=(p_x, p_y), angle=angle))

    def on_touch_down(self, touch):
        self.oy = (touch.y - self.center[1])
        self.ox = (touch.x - self.center[0])
        return super(Ring, self).on_touch_down(touch)

    def on_touch_move(self, touch):
        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        r_sq = x ** 2 + y ** 2
        outer_r_sq = (3 * 150 / 2 + 35) ** 2
        inner_r_sq = (3 * 150 / 2 - 35) ** 2
        if r_sq > outer_r_sq or r_sq < inner_r_sq:
            return super(Ring, self).on_touch_move(touch)
        new_angle = math.degrees(math.atan2(y, x))
        old_angle = math.degrees(math.atan2(self.oy, self.ox))
        delta_angle = new_angle - old_angle
        self.angle += delta_angle
        self.oy = (touch.y - self.center[1])
        self.ox = (touch.x - self.center[0])
        return super(Ring, self).on_touch_move(touch)


class Ringa(Widget):
    angle = NumericProperty(0)
    def __init__(self, **kwargs):
        super(Ringa, self).__init__(**kwargs)
        pi = math.pi
        txsize_x = 50
        txsize_y = 30
        r = 150
        div = 20
        for i in range(1, div):
            angle = 360.0 / (div - 1) * i
            p_x = (Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) * r) - txsize_x / 2
            p_y = (Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) * r) - txsize_y / 2
            self.add_widget(
                RotatableTI(text="hi" + str(i), size=(txsize_x, txsize_y), pos=(p_x, p_y), angle=angle))

    def on_touch_down(self, touch):
        self.oy = (touch.y - self.center[1])
        self.ox = (touch.x - self.center[0])
        return super(Ringa, self).on_touch_down(touch)

    def on_touch_move(self, touch):
        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        r_sq = x ** 2 + y ** 2
        outer_r_sq = (150 + 25) ** 2
        inner_r_sq = (150 - 25) ** 2
        if r_sq > outer_r_sq or r_sq < inner_r_sq:
            return super(Ringa, self).on_touch_move(touch)
        new_angle = math.degrees(math.atan2(y, x))
        old_angle = math.degrees(math.atan2(self.oy, self.ox))
        delta_angle = new_angle - old_angle
        self.angle += delta_angle
        self.oy = (touch.y - self.center[1])
        self.ox = (touch.x - self.center[0])
        return super(Ringa, self).on_touch_move(touch)


class Scat(FloatLayout):
    Window.size = (680, 680)
    angle = NumericProperty(0)

    def __init__(self, **kwargs):
        super(Scat, self).__init__(**kwargs)
        ring1 = ObjectProperty(None)
        ring2 = ObjectProperty(None)

class Mainn(App):
    def build(self):
        return Scat()


if __name__ == "__main__":
    Mainn().run()

Note that you could combine the Ring and Ringa classes into one class with properties of txsize_x, txsize_y, r, and div (in addition to angle).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 John Anderson