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()

请注意,您可以将 RingRinga class 组合成一个具有 txsize_xtxsize_y 属性的 class, rdiv(除了 angle)。