'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 |
