如何在纯 Python 代码(不是 kvlang)中使用 Kivy Rotate?

How to use Kivy Rotate in pure Python code (not kvlang)?

我想使用纯 python 代码而不是 kvlang 来旋转按钮。

使用 kvlang 我们可以旋转按钮,如 example 所示。 按钮围绕其自身中心旋转 45 度。原代码如下:

from kivy.app import App
from kivy.lang import Builder
kv = '''
FloatLayout:
    Button:
        text: 'hello world'
        size_hint: None, None
        pos_hint: {'center_x': .5, 'center_y': .5}
        canvas.before:
            PushMatrix
            Rotate:
                angle: 45
                origin: self.center
        canvas.after:
            PopMatrix
'''
class RotationApp(App):
    def build(self):
        return Builder.load_string(kv)
RotationApp().run()

但是当我尝试使用如下所示的纯 python 代码重写此示例时,按钮在其他地方旋转,如图 here:

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.graphics import PushMatrix, PopMatrix, Rotate
class MyButton(Button):
    def __init__(self):
        super().__init__()
        self.text = 'hello world'
        self.size_hint = (None, None)
        self.pos_hint = {'center_x': .5, 'center_y': .5}
        with self.canvas.before:
            PushMatrix()
            Rotate(origin=self.center, angle=45)
        with self.canvas.after:
            PopMatrix()
class RotationApp(App):
    def __init__(self):
        super().__init__()
        self.layout = FloatLayout()
        self.button = MyButton()
        self.layout.add_widget(self.button)
    def build(self):
        return self.layout
RotationApp().run()

以上两段代码产生的结果不同。我们有没有做错什么?

更新:

按照@inclement的提示解题,解法如下:

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.button import Button
from kivy.graphics import PushMatrix, PopMatrix, Rotate
class MyButton(Button):
    def __init__(self):
        super().__init__()
        self.text = 'hello world'
        self.size_hint = (None, None)
        self.pos_hint = {'center_x': .5, 'center_y': .5}
        with self.canvas.before:
            PushMatrix()
            
            # Rotate(origin=self.center, angle=45)  # previous approach
            self.rotation = Rotate(origin=self.center, angle=45)
            self.bind(center=lambda _, value: setattr(self.rotation, "origin", value))
            
        with self.canvas.after:
            PopMatrix()
class RotationApp(App):
    def __init__(self):
        super().__init__()
        self.layout = FloatLayout()
        self.button = MyButton()
        self.layout.add_widget(self.button)
    def build(self):
        return self.layout
RotationApp().run()

在您的 Python 代码中,self.center__init__ 期间仅计算一次。在kv代码中,会自动创建一个绑定来重置Rotate指令的origin属性每次改变。

您需要将缺少的功能放入 Python 代码中,例如 self.rotation = Rotate(...)self.bind(center=lambda instance, value: setattr(self.rotation, "origin", value))(尽管我相信您可以想出更好的方法来设置它向上,这只是内联示例)。