【问题标题】:Kivy, reusing a toggle button layout, but assigning different functions to the buttonsKivy,重用切换按钮布局,但为按钮分配不同的功能
【发布时间】:2021-01-03 14:58:45
【问题描述】:

我创建了一个自定义切换按钮布局,我想多次重复使用它。我想重用它,因为它包含广泛的格式。我正在使用生成的 uuid 来分配组,以便多个实例不会相互干扰。

这是我的 test.kv:

#:kivy 2.0.0
#:import uuid uuid

<ExampleToggle@BoxLayout>:
    uuid: uuid.uuid4()
    orientation: 'horizontal'

    ToggleButton:
        id: run
        text: 'RUN'
        group: root.uuid
        on_release: root.on_run()

    ToggleButton:
        id: stop
        text: 'STOP'
        group: root.uuid
        on_release: root.on_stop()

<TestDisplay>:
    BoxLayout:
        orientation: 'vertical'
        
        ExampleToggle:
            on_run: print('A') 
            on_stop: print('B') 

        ExampleToggle:
            on_run: print('C') 
            on_stop: print('D') 

这是我的 test.py:

import kivy
kivy.require('2.0.0')

from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.widget import Widget


class ExampleToggle():
    on_run = ObjectProperty(None)
    on_stop = ObjectProperty(None)

    def on_run(self, *args):
        # Dummy function
        pass

    def on_stop(self, *args):
        # Dummy function
        pass


class TestDisplay(Widget):
    pass


class TestApp(App):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)

    def build(self):
        return TestDisplay()


if __name__ == '__main__':
    TestApp().run()

我希望能够创建 ExampleToggle 小部件的多个副本并为按钮分配不同的功能。将函数分配给各个按钮的 on_release 事件没有问题,但是如果我这样做,那么对于此小部件的每个实例来说,它都是相同的事件。我希望能够在每次重用小部件时分配不同的功能。

我觉得我要么错过了一些非常简单的事情,要么我走错了路。我尝试了多种不同的方法,并花费了大量时间阅读和研究...任何帮助将不胜感激。

【问题讨论】:

    标签: kivy custom-widgets


    【解决方案1】:

    您只需要提供一种在运行时设置调用的函数的方法。

    例如,您可以在 ExampleToggle Python 代码中包含 f1 = ObjectProperty()f2 = ObjectProperty(),然后在 kv 代码中包含 on_release: root.f1() 等。要设置函数,在kv中使用f1: do_something_a,在python中使用your_exampletoggle.f1 = do_something_a,其中do_something_a是一个函数。

    【讨论】:

    • 感谢您的提示,可悲的是,这就是我开始的。但是,当我运行此代码时,我收到: AttributeError: run File "/home/ourlogon/.local/lib/python3.6/site-packages/kivy/lang/builder.py", line 730, in _apply_rule raise AttributeError(key )。错误指向 text.kv 文件“on_run: print('A')”中的第 25 行。我已经用一个示例更新了我的问题,该示例将演示该错误。
    • 从您的 ExampleToggle kv 规则中删除 @BoxLayout
    • on_run: print('A')on_run 绑定到值 None 因为这是 print 语句的结果。您需要在那里编写一个函数,例如lambda: print('A').
    【解决方案2】:

    经过长时间的休息后,我回到了这个问题并找到了答案。这是我为其他好奇的人或未来自己的工作解决方案。我必须在 python 中构建切换布局,然后在 .kv 文件中使用它。关键是使用“self.dispatch()”方法。我通过阅读按钮的 kivy 源代码发现了这一点。

    test.kv:

    #:kivy 2.0.0
    #:import uuid uuid
    #:import ExampleToggle test
    
    <TestDisplay>:
        BoxLayout:
            orientation: 'vertical'
            
            ExampleToggle:
                on_run: print('A') 
                on_stop: print('B') 
    
            ExampleToggle:
                on_run: print('C') 
                on_stop: print('D') 
    

    test.py:

    from uuid import uuid4
    
    import kivy
    kivy.require('2.0.0')
    
    from kivy.app import App
    from kivy.uix.widget import Widget
    from kivy.uix.togglebutton import ToggleButton
    from kivy.uix.boxlayout import BoxLayout
    
    
    class ExampleToggle(BoxLayout):
        def __init__(self, **kwargs):
            self.register_event_type('on_run')
            self.register_event_type('on_stop')
    
            super(ExampleToggle, self).__init__(**kwargs)
    
            self.groupid = uuid4()
            self.orientation = 'horizontal'
            self.size_hint = (None, .1)
            self.width: self.height * 5
            self.state = None
    
            rbtn = ToggleButton(text='RUN',
                                group=self.groupid,
                                allow_no_selection=False)
            sbtn = ToggleButton(text='STOP',
                                group=self.groupid,
                                allow_no_selection=False)
    
            self.add_widget(rbtn)
            self.add_widget(sbtn)
    
            rbtn.bind(on_release=self.run)
            sbtn.bind(on_release=self.stop)
    
        def run(self, *args):
            if self.state != 'RUN':
                self.dispatch('on_run')
                self.state = 'RUN'
    
        def stop(self, *args):
            if self.state != 'STOP':
                self.dispatch('on_stop')
                self.state = 'STOP'
    
        def on_run(self):
            pass
    
        def on_stop(self):
            pass
    
    
    class TestDisplay(Widget):
        pass
    
    
    class TestApp(App):
        def __init__(self, **kwargs):
            super().__init__(**kwargs)
    
        def build(self):
            return TestDisplay()
    
    
    if __name__ == '__main__':
        TestApp().run()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-09-26
      • 1970-01-01
      • 1970-01-01
      • 2019-03-13
      • 2021-09-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多