如何在 kivy 中旋转文本框并在 polar 中排列它们

how to rotate textboxes in kivy and arrange them in polar

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

为了更好的理解,这里有一张图:

import math
from kivy.uix.scatter import Scatter
from kivy.app import App
from kivy.graphics import *
from kivy.core.window import Window
from kivy.uix.widget import Widget
from kivy.uix.button import Button

pi = math.pi

class RotateMe(Button):
    def __init__(self, **kwargs):
        Button.__init__(self, **kwargs)

        with self.canvas.before:
            PushMatrix()
            self.rot = Rotate(angle= 45, origin= self.center)

        with self.canvas.after:
            PopMatrix()

class Scat(Scatter):
    Window.size = (600, 600)
    def __init__(self,**kwargs):
        super(Scat,self).__init__(**kwargs)
        with self.canvas:
            p_x=0
            p_y=0
            b=0
            r=150
            div=20
            pt = []
            for i in range(div):
                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
                #print(p)
                pt.append(p_x)
                pt.append(p_y)
                if i>0:
                    Color(1,0,0,1)
                    #print(pt)
                    #Line(points=[pt[2*i-2],pt[2*i-1],pt[2*i],pt[2*i+1]],width=3)
                    self.add_widget(Button(text="hi",size=(50,30),pos=(pt[2*i-2],pt[2*i-1])))
                    #self.rotation(10)

class Main(App,Widget):
    def build(self):
        return Scat()

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

困难在于 TextInput(与许多 Kivy 小部件一样)有自己的 canvas 指令来定义为其绘制的框。因此,当您进行旋转时,不会影响绘制方框的 canvas 指令。您可以通过使用 kv 语言重新定义 TextInput 的所有 canvas 指令来解决这个问题。这是您的代码的修改版本:

import math
from kivy.lang import Builder
from kivy.properties import NumericProperty
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

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

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

class Main(App,Widget):
    def build(self):
        Builder.load_string(kv)
        return Scat()

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

kv中,在<-RotatableTI>中的-表示不使用TextInput的默认canvas指令。所以我的 kv 字符串中的 canvas 指令主要是默认指令(从 style.kv 复制),添加了旋转内容。为了简单起见,我还使 Scat 扩展 FloatLayout 而不是 Scatter

您的角度计算也有误。我替换了:

2 * pi / div-1 * i

与:

2 * pi / (div-1) * i