【问题标题】:How do I set different properties for different instances of ListView in a Kivy App?如何在 Kivy 应用程序中为不同的 ListView 实例设置不同的属性?
【发布时间】:2017-01-04 12:50:01
【问题描述】:

我希望我的 Kivy 应用有多个 ListView 实例。在分配不同的属性时,我被卡住了,尤其是回调。以下代码说明了我的问题:

from kivy.app import App
from kivy.uix.listview import ListItemButton
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang import Builder

Builder.load_string('''
#: import ListAdapter kivy.adapters.listadapter.ListAdapter
#: import ListItemButton kivy.uix.listview.ListItemButton
<smRoot>:
    Screen1:
    Screen2:
<ListItemButton>:
    on_press: app.callback1(self)
    height: dp(25)
    size_hint: (1,.1)
<Screen1>:
    name:'screen1'
    BoxLayout:
        orientation: 'vertical'
        Label:
            text: 'Screen1'
            size_hint_y: .1
        ListView:
            id:lstScreen1    
            adapter:
                ListAdapter(data=[{'text':'item1'},{'text':'item2'},{'text':'item3'}],
                args_converter=lambda row_index, rec: {'text': rec['text']},
                cls=ListItemButton,
                selection_mode='single',
                allow_empty_selection=False)
        Button:
            text: 'Switch Screen'
            size_hint_y: .1
            on_press: root.manager.current = 'screen2'
<ListItemButton>:
    on_press: app.callback2(self)
    height: dp(25)
    size_hint: (1,.1)            
<Screen2>:
    name:'screen2'
    BoxLayout:
        orientation: 'vertical'
        Label:
            text: 'Screen2'
            size_hint_y: .1
        ListView:
            id:lstScreen2    
            adapter:
                ListAdapter(data=[{'text':'item1'},{'text':'item2'},{'text':'item3'}],
                args_converter=lambda row_index, rec: {'text': rec['text']},
                cls=ListItemButton,
                selection_mode='single', 
                allow_empty_selection=False)
        Button:
            text: 'Switch Screen'
            size_hint_y: .1
            on_press: root.manager.current = 'screen1'
''')

class smRoot(ScreenManager):
    pass

class Screen1(Screen):
    MyButt = ListItemButton
    pass

class Screen2(Screen):
    pass

class myApp(App):
    def build(self):
        smroot = smRoot()
        return smroot

    def callback1(self, btn_instance):
        index = btn_instance.index
        print 'From Screen 1: ' + str(index)

    def callback2(self, btn_instance):
        index = btn_instance.index
        print 'From Screen 2: ' + str(index)

myApp().run()

在这里,我希望屏幕 1 和 2 上的每个 ListView 实例都有单独的回调。但是当我点击任一屏幕时,输出都是一样的,就像这样:

From Screen 2: 0
From Screen 1: 0

理想情况下,我希望实现类似Dynamic Class 的东西。但是当我尝试这样的事情时:

<MyButt@ListItemButton>:
    #on_press: app.callback1(self)
    height: dp(25)
    size_hint: (1,.1)
<Screen1>:
    name:'screen1'
    MyButt:
        on_press: app.callback1(self)
    BoxLayout:
        orientation: 'vertical'
        Label:
            text: 'Screen1'
            size_hint_y: .1
        ListView:
            id:lstScreen1    
            adapter:
                ListAdapter(data=[{'text':'item1'},{'text':'item2'},{'text':'item3'}],
                args_converter=lambda row_index, rec: {'text': rec['text']},
                cls=MyButt,
                selection_mode='single',
                allow_empty_selection=False)

我收到NameError: name 'MyButt' is not defined 错误。据我所知,我在上面链接的文档示例中遵循了相同的语法,所以我很困惑。

我没有尝试在 Python 中创建自定义类,但我宁愿在 .kv 代码中保留 UI 元素(如果我没记错的话,这不是 kv 背后的基本思想吗?)。

在这方面的任何帮助/指针/建议将不胜感激。

【问题讨论】:

    标签: android python listview kivy kivy-language


    【解决方案1】:

    你不能在不导入的情况下在 kv 中使用 python 端的小部件类(在“:”之后),但是由于 MyButt 没有在任何模块中定义,作为一个动态类(在纯 kv 中定义)你可以使用Factory来使用。

    首先,在您的 kv 文件顶部导入 Factory。

    #:import Factory kivy.factory.Factory
    

    然后改变

        ListView:
            id:lstScreen1    
            adapter:
                ListAdapter(data=[{'text':'item1'},{'text':'item2'},{'text':'item3'}],
                args_converter=lambda row_index, rec: {'text': rec['text']},
                cls=MyButt,
    

        ListView:
            id:lstScreen1    
            adapter:
                ListAdapter(data=[{'text':'item1'},{'text':'item2'},{'text':'item3'}],
                args_converter=lambda row_index, rec: {'text': rec['text']},
                cls=Factory.MyButt,
    

    【讨论】:

    • 谢谢!一个快速的后续问题:这是否意味着如果括号中的所有内容都可以避免这种情况,即ListAdapter(data=...)been 而是使用 kv 而不是 Python 声明...?一般来说,这会是推荐的做法吗?
    • 如果可以在 kv 中做同样的事情,是的,它可以避免使用工厂和导入等……但是 kivy 在这里不允许这样做,因为您必须将其分配给一个属性,因此您的代码位于分配的“右侧”,在 kvlang 中,此右侧(“:”的右侧)由 python 直接评估,因此对于该特定问题没有更好的解决方案.简而言之,KVlang 最擅长声明小部件,而不是像 ListAdapter 这样的其他类。
    猜你喜欢
    • 2019-01-08
    • 1970-01-01
    • 1970-01-01
    • 2014-09-16
    • 2019-09-13
    • 1970-01-01
    • 2016-06-18
    • 2012-02-26
    • 1970-01-01
    相关资源
    最近更新 更多