Python Kivy - 跨不同的调用方法 class

Python Kivy - Call methods across different class

我是编码新手,与 Python 一起工作了几个月,并试图全神贯注于 Kivy。我认为有一个简单的解决方案,但在从一个 class 中调用另一个方法时,我很挣扎。甚至不确定这是否可能,我的 OOP 不会很强!!

如果有人能向我解释一下,我将不胜感激!我在网上看过,但仍在努力了解我需要做什么。

我有一个简单的代码,它有一个标签和 3 个切换按钮,标签文本会更改以显示按下了多少个切换按钮。下面是原代码。

我正在尝试使用循环创建切换按钮,以便可以轻松更改切换按钮的数量。我已经实现了这一点,但是当我尝试将该方法绑定到切换按钮时,代码失败了。我还尝试在“Tbtn”class 中定义一个方法来调用 Main.Counter() 但这也不起作用。

    self.bind(on_state = Main.counter())

在切换按钮的 init 中我认为是我出错的地方。

任何帮助甚至是解释都会很棒。这不是我第一次被困在这上面了!!谢谢

原码:

from kivy.app import App
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import NumericProperty

class Tbtn(ToggleButton):
    pass

class Header_Box(BoxLayout):
    pass

class Counter(BoxLayout):
    pass

class Main(BoxLayout):
    count = NumericProperty()

    def counter(self,widget):
        toggles = []
        for child in self.ids.Seat_Box.children:
            if isinstance(child, ToggleButton):
                if child.state == 'down':
                    toggles.append(child.text)
        self.count = len(toggles)
        print(self.count)


class TestApp(App):
    def build(self):
        return Main()

TestApp().run()

KV文件:

<Main>:
    name: "main"
    BoxLayout:

        orientation: "vertical"
        Header_Box:
            Label:
                text: str(root.count)

        Counter:
            id: Seat_Box            
            Tbtn:
                id: btn1
                on_state: root.counter(self)
            Tbtn:
                id: btn2
                on_state: root.counter(self)
            Tbtn:
                id: btn2
                on_state: root.counter(self)

for 循环代码:

from kivy.app import App
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import NumericProperty

class Tbtn(ToggleButton):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        self.bind(on_state = Main().counter())

class Header_Box(BoxLayout):
    pass

class Counter(BoxLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

        for x in range(3):
            btn = Tbtn()
            self.add_widget(btn)

class Main(BoxLayout):
    count = NumericProperty()

    def counter(self,widget):
        toggles = []
        for child in self.ids.Seat_Box.children:
            if isinstance(child, ToggleButton):
                if child.state == 'down':
                    toggles.append(child.text)
        self.count = len(toggles)
        print(self.count)


class TestApp(App):
    def build(self):
        return Main()

TestApp().run()

KV 文件:

<Main>:
    name: "main"
    BoxLayout:

        orientation: "vertical"
        Header_Box:
            Label:
                text: str(root.count)

        Counter:
            id: Seat_Box      

首先,删除 self.bind(on_state = Main().counter())

我建议你在 .kv 端解决这个问题。

方式 1-.kv 侧: 在您的 .kv 文件下方添加:

<Tbtn>:
    on_state: app.get_running_app().root.counter(self)

Way 2-.py side: 在 Tbtn 添加这个 class.

def on_release(self):
    App.get_running_app().root.counter(self)

虽然其他答案已经解决了你的问题,但下面的答案让我 post 这个问题。

Any help and even an explanation would be great...

从技术上讲,下面一行,

self.bind(on_state = Main().counter())

由于各种原因是错误的。让我们试着弄清楚这一点。

方法 on_state 是一种通用方法,而不是默认方法 event(如 on_press 等)。这就是 bind(on_state = some_callback) 不起作用的原因。

你又做了 Main().counter(),它实际上创建了 Main 的一个新实例(它可能与 root 相关,也可能不相关,这里当然不是)并赋值到它的方法。

您似乎只想访问 Main 小部件(恰好是此处的 root 小部件)方法之一。

由于您使用了 kvlang,可以按如下方式更有效地完成此操作,

<Tbtn>:
    on_state: app.root.counter()

您可以在 kvlang doc.

中找到更多相关信息

现在在 .py 中,您只需定义 class 以及其他一些更改,

class Tbtn(ToggleButton):
    pass
.
.
.
class Main(BoxLayout):
    count = NumericProperty()

    def counter(self): # Pass no extra args as you haven't done in 'on_state' method.
        toggles = []
        .
        .
        .