У меня есть код, который создает несколько колец, состоящих из текстовых вводов. Я хочу выбрать каждое кольцо по отдельности, чтобы вращать их вокруг своего полюса, но они выбираются вместе в touch_move. Я использую некоторые части «Учебника по игре в понг» (который доступен на: https://kivy.org/doc/stable/tutorials/pong.html), чтобы выяснить, как работает touch_move, и выбрать индивидуально, но это тоже не работает. В чем проблема кода, который не может выделить и переместить каждое кольцо, чтобы потом можно было вращать каждое из них по отдельности полярно? Я должен упомянуть, что в 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
нет кода для этого. Вы должны добавить свойство angle
к классам Ring
, а также инструкции 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
в один класс со свойствами txsize_x
, txsize_y
, r
и div
(в дополнение к angle
).
спасибо, дорогой Джон, ты решаешь основную проблему, о которой я просил, но все же текстовые вводы после поворота выбираются по их начальной позиции, а не по их новой позиции после поворота!