在 kivy 中围绕中心点旋转圆形排列的小部件

发布于 2025-01-12 02:02:08 字数 6970 浏览 0 评论 0原文

我有一些排列成圆形的文本输入,我正在寻找一种方法来围绕它们的中心旋转这些小部件的整个包,就像轮子一样,在其中的一部分上拖动鼠标。我尝试结合在某些页面中找到的一些代码,但不知道如何使其正常工作。

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

pi = math.pi

kv = '''
<-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
        
<Dial>:
    canvas:
        Rotate:
            angle: self.angle
            origin: self.center

'''
Builder.load_string(kv)

class Circle(Widget):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            pass

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

class Scat(FloatLayout,Widget):
    Window.size = (600, 600)
    def __init__(self, **kwargs):
        super(Scat, self).__init__(**kwargs)
        p_x = 0
        p_y = 0
        b = 0
        r = 150
        div = 20
        pt = []
        for i in range(div):
            angle = 360.0 / (div - 1) * i
            p_x = Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) * r
            p_y = Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) * r
            pt.append(p_x)
            pt.append(p_y)
            if i > 0:
                self.add_widget(RotatableTI(text="hi" + str(i), size=(50, 30), pos=(p_x, p_y), angle=angle))
                
    angle = NumericProperty(0)
    def on_touch_down(self, touch):

        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        self.prev_angle = calc if calc > 0 else 360+calc
        self.tmp = self.angle

        return super(Scat, self).on_touch_down(touch) # dispatch touch event futher

    def on_touch_move(self, touch):
        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        new_angle = calc if calc > 0 else 360+calc

        self.angle = self.tmp + (new_angle-self.prev_angle)%360

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

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

我想在 kivy 中对一些文本输入进行极坐标排列,但只找到一种在分散类中通过鼠标拖动来旋转文本输入的方法。我所有的尝试都达到了一个不旋转的文本输入,只有当我输入文本时,文本才会显示旋转(没有旋转的文本输入框!),并且看起来不太好,所以我正在寻找更好的方法,我可以接近带按钮的解决方案,但它们并不完全是我想要的,只是它们的位置是极性的,而不是它们的方向。有没有办法让 textInputs 像描述的那样进行数组?

最后,我正在寻找一种方法,拥有 3 或 4 个旋转的文本输入包,我想知道鼠标拖动会识别出其中哪一个是完美选择的,还是有时错误选择的?因为当我想用鼠标旋转 kivy 中的一个项目时,如果选择对象边框的外部仍然可以选择并旋转它。

编辑 亲爱的约翰·安德森的回应,向前迈出了一步;但效果仍然不好。我在第二张图片中提到了下面的问题(在代码下方)。

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

pi = math.pi

kv = '''

<Scat>:
    canvas.before:
        PushMatrix
        Rotate:
            angle: self.angle
            origin: self.center
    canvas.after:
        PopMatrix
<-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
        
    canvas:
        Rotate:
            angle: self.angle
            origin: self.center

'''
Builder.load_string(kv)

class Circle(Widget):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            pass

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

class Scat(FloatLayout):
    Window.size = (600, 600)
    def __init__(self, **kwargs):
        super(Scat, self).__init__(**kwargs)
        p_x = 0
        p_y = 0
        b = 0
        r = 150
        div = 20
        pt = []
        for i in range(div):
            angle = 360.0 / (div - 1) * i
            p_x = Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) * r
            p_y = Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) * r
            pt.append(p_x)
            pt.append(p_y)
            if i > 0:
                self.add_widget(RotatableTI(text="hi" + str(i), size=(50, 30), pos=(p_x, p_y), angle=angle))

    angle = NumericProperty(0)
    def on_touch_down(self, touch):

        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        self.prev_angle = calc if calc > 0 else 360+calc
        self.tmp = self.angle

        return super(Scat, self).on_touch_down(touch) # dispatch touch event futher

    def on_touch_move(self, touch):
        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        new_angle = calc if calc > 0 else 360+calc

        self.angle = self.tmp + (new_angle-self.prev_angle)%360

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

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

除了该环之外,除了轨道运动之外,它还向其他方向移动(其中心点不是永久的,可以通过拖动来改变它),这是意想不到的! [1]: https://i.sstatic.net/3jhQ8.png [2]: https://i.sstatic.net/Mrpf7.png

I have some Textinputs that arranged circular and i am looking for a way to spin the whole package of these widgets around their center like a wheel with dragging mouse on part of them. i try to combine some codes that i found in some pages but have no idea how to make this works properly.

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

pi = math.pi

kv = '''
<-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
        
<Dial>:
    canvas:
        Rotate:
            angle: self.angle
            origin: self.center

'''
Builder.load_string(kv)

class Circle(Widget):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            pass

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

class Scat(FloatLayout,Widget):
    Window.size = (600, 600)
    def __init__(self, **kwargs):
        super(Scat, self).__init__(**kwargs)
        p_x = 0
        p_y = 0
        b = 0
        r = 150
        div = 20
        pt = []
        for i in range(div):
            angle = 360.0 / (div - 1) * i
            p_x = Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) * r
            p_y = Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) * r
            pt.append(p_x)
            pt.append(p_y)
            if i > 0:
                self.add_widget(RotatableTI(text="hi" + str(i), size=(50, 30), pos=(p_x, p_y), angle=angle))
                
    angle = NumericProperty(0)
    def on_touch_down(self, touch):

        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        self.prev_angle = calc if calc > 0 else 360+calc
        self.tmp = self.angle

        return super(Scat, self).on_touch_down(touch) # dispatch touch event futher

    def on_touch_move(self, touch):
        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        new_angle = calc if calc > 0 else 360+calc

        self.angle = self.tmp + (new_angle-self.prev_angle)%360

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

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

I want to array polar some textinputs in kivy but only find a way to rotate textinput with mouse dragging in scatter class. all of my try reached to a textinput that is not rotated and only when I type in it the text shows rotated(with not rotated textinput box!), and not looks good, so im looking for a better way, I could reach close to solution with buttons, but they are not exactly I want and just their position are polar, not their orirntation. is there any way for textInputs to array like described?

at the end im looking for a way have 3 or 4 of this whirling packages of textinputs and I am wondering mouse dragging would recognize which one of them selected perfectly or selected sometimes wrongly? because when i want spin one item in kivy with mouse, if select the outside of object`s border still can select and rotate it.

EDITED
one step forward with response of dear John Anderson; but still works not good. i mention the problems below(under of the code) in the second picture.

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

pi = math.pi

kv = '''

<Scat>:
    canvas.before:
        PushMatrix
        Rotate:
            angle: self.angle
            origin: self.center
    canvas.after:
        PopMatrix
<-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
        
    canvas:
        Rotate:
            angle: self.angle
            origin: self.center

'''
Builder.load_string(kv)

class Circle(Widget):
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            pass

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

class Scat(FloatLayout):
    Window.size = (600, 600)
    def __init__(self, **kwargs):
        super(Scat, self).__init__(**kwargs)
        p_x = 0
        p_y = 0
        b = 0
        r = 150
        div = 20
        pt = []
        for i in range(div):
            angle = 360.0 / (div - 1) * i
            p_x = Window.size[0] / 2 + math.cos(2 * pi / (div - 1) * i) * r
            p_y = Window.size[1] / 2 + math.sin(2 * pi / (div - 1) * i) * r
            pt.append(p_x)
            pt.append(p_y)
            if i > 0:
                self.add_widget(RotatableTI(text="hi" + str(i), size=(50, 30), pos=(p_x, p_y), angle=angle))

    angle = NumericProperty(0)
    def on_touch_down(self, touch):

        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        self.prev_angle = calc if calc > 0 else 360+calc
        self.tmp = self.angle

        return super(Scat, self).on_touch_down(touch) # dispatch touch event futher

    def on_touch_move(self, touch):
        y = (touch.y - self.center[1])
        x = (touch.x - self.center[0])
        calc = math.degrees(math.atan2(y, x))
        new_angle = calc if calc > 0 else 360+calc

        self.angle = self.tmp + (new_angle-self.prev_angle)%360

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

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

beside that ring except orbiting moves other directions(its center point is not permanent and can change it with dragging) that its not expected!
[1]: https://i.sstatic.net/3jhQ8.png
[2]: https://i.sstatic.net/Mrpf7.png

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情场扛把子 2025-01-19 02:02:08

您几乎可以进行轮换工作。只需将其添加到您的 kv 中:

<Scat>:
    canvas.before:
        PushMatrix
        Rotate:
            angle: self.angle
            origin: self.center
    canvas.after:
        PopMatrix

另外,

class Scat(FloatLayout,Widget):

应该只是:

class Scat(FloatLayout):

因为 FloatLayout 是一个 Widget

如果您打算使用多个 Scat 小部件,则应使用 collide_point() 来确定哪个实例被触摸。

You almost have the rotation working. Just add this to your kv:

<Scat>:
    canvas.before:
        PushMatrix
        Rotate:
            angle: self.angle
            origin: self.center
    canvas.after:
        PopMatrix

Also,

class Scat(FloatLayout,Widget):

should be just:

class Scat(FloatLayout):

because FloatLayout is a Widget.

If you intend to use several Scat Widgets, you should use collide_point() to determine which instance is being touched.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文