kivy touch_move 如何区分对象?
How kivy touch_move distincts between objects?
我有一个代码可以生成一些由文本输入组成的环。我想 select 每个圆环分别绕着它们的极点旋转,但它们 select 在一起 touch_move。我使用“Pong Game Tutorial”(在 https://kivy.org/doc/stable/tutorials/pong.html 上可用)的某些部分来弄清楚 touch_move 和 select 是如何工作的,但这也不起作用。不能 select 和移动每个环的代码有什么问题,然后可以单独旋转它们中的每一个?我应该提到在 touch_move 中,我评论了为旋转极环(这是主要目的)编写的最后一次尝试。
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()
您的代码目前无法旋转 Ring
对象,因为 Ring
classes 中没有代码可以执行此操作。您必须将 angle
属性 添加到 Ring
classes,以及 canvas
指令以根据该角度和 on_touch_move()
方法调整 angle
值。这是您的代码的修改版本:
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()
请注意,您可以将 Ring
和 Ringa
class 组合成一个具有 txsize_x
、txsize_y
属性的 class, r
和 div
(除了 angle
)。
我有一个代码可以生成一些由文本输入组成的环。我想 select 每个圆环分别绕着它们的极点旋转,但它们 select 在一起 touch_move。我使用“Pong Game Tutorial”(在 https://kivy.org/doc/stable/tutorials/pong.html 上可用)的某些部分来弄清楚 touch_move 和 select 是如何工作的,但这也不起作用。不能 select 和移动每个环的代码有什么问题,然后可以单独旋转它们中的每一个?我应该提到在 touch_move 中,我评论了为旋转极环(这是主要目的)编写的最后一次尝试。
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()
您的代码目前无法旋转 Ring
对象,因为 Ring
classes 中没有代码可以执行此操作。您必须将 angle
属性 添加到 Ring
classes,以及 canvas
指令以根据该角度和 on_touch_move()
方法调整 angle
值。这是您的代码的修改版本:
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()
请注意,您可以将 Ring
和 Ringa
class 组合成一个具有 txsize_x
、txsize_y
属性的 class, r
和 div
(除了 angle
)。