简体   繁体   English

Python Kivy - 跨不同调用方法 class

[英]Python Kivy - Call methods across different class

I am new to coding, a few months with Python and trying to wrap my head around Kivy. I think there is a simple solution to this but I am struggling when it comes to calling a method in one class from another.我是编码新手,与 Python 一起工作了几个月,并试图全神贯注于 Kivy。我认为对此有一个简单的解决方案,但在从另一个 class 中调用方法时,我很挣扎。 Not even sure if this is possible, my OOP wouldn't be very strong!!甚至不确定这是否可能,我的 OOP 不会很强!!

Would appreciate if someone could explain this to me.如果有人能向我解释这一点,我将不胜感激。 I've looked online but still struggling to understand what I need to do.我在网上看过,但仍在努力了解我需要做什么。

i have a simple code that had a label and 3 toggle buttons, the label text changes to show how many toggle buttons are pressed.我有一个简单的代码,它有一个 label 和 3 个切换按钮,label 文本更改以显示按下了多少个切换按钮。 Below is the original code.下面是原始代码。

What I am trying to do create the toggle buttons using a loop so that the number of toggle buttons can be easily altered.我想要做的是使用循环创建切换按钮,以便可以轻松更改切换按钮的数量。 i have achieved this but when I try and bind the method to the toggle button the code fails with.我已经实现了这一点,但是当我尝试将该方法绑定到切换按钮时,代码失败了。 I also tried defining a method within the "Tbtn" class to call the Main.Counter() but this didn't work either.我还尝试在“Tbtn”class 中定义一个方法来调用 Main.Counter(),但这也不起作用。

The line线路

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

in the init of the toggle button is where i am going wrong I think.我认为在切换按钮的初始部分是我出错的地方。

Any help and even an explanation would be great.任何帮助甚至解释都会很棒。 Not the first time I have been stuck on this!!这不是我第一次被困在这上面了!! Thanks谢谢

Original Code:原始代码:

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

The KV file: 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)

Code with for Loop:使用 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 file: KV文件:

<Main>:
    name: "main"
    BoxLayout:

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

        Counter:
            id: Seat_Box      

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

I suggest you to solve this in.kv side.我建议你解决这个 in.kv 方面。

Way 1-.kv side: Add this below your.kv file:方式 1-.kv 端:在您的 .kv 文件下方添加:

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

Way 2-.py side: Add this in Tbtn class. Way 2-.py side:在Tbtn class中添加这个。

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

Although the other answer already solved your issue, the following made me post this one.虽然其他答案已经解决了您的问题,但以下内容让我发布了这个问题。

Any help and even an explanation would be great...任何帮助甚至解释都会很棒......

Technically the following line,从技术上讲,以下行,

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

is wrong for various reasons.由于各种原因是错误的。 Let's try to figure this out.让我们试着弄清楚这一点。

The method on_state is kind of generic one not a default event (like on_press etc.). on_state方法是一种通用方法,不是默认事件(如on_press等)。 That's why bind(on_state = some_callback) won't work.这就是为什么bind(on_state = some_callback)不起作用的原因。

Again you did Main().counter() which actually creates a new instance of Main (which may or may not be related to the root , and here it's of course not) and assigned to its method.您再次执行Main().counter() ,它实际上创建了Main的一个新实例(它可能与root相关,也可能不相关,这里当然不是)并分配给它的方法。

It seems you want to just access one of Main widget's (which happens to be the root widget here) method.您似乎只想访问Main小部件(恰好是此处的root小部件)方法之一。

Since you used kvlang , this could be done more efficiently as follows,由于您使用kvlang ,因此可以按如下方式更有效地完成此操作,

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

You can find more about this in the kvlang doc .您可以在kvlang文档中找到更多相关信息。

Now in .py you just define the class along with some other changes,现在在.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 = []
        .
        .
        .

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM