【问题标题】:kivy crash if widget used in kv file, succeeds if used in Python file如果小部件在 kv 文件中使用,kivy 崩溃,如果在 Python 文件中使用则成功
【发布时间】:2013-10-24 09:57:51
【问题描述】:

我遇到了以下问题:

示例(mainok.py、testok.kv)启动成功,

$ cat mainok.py
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
class BuddyList(BoxLayout):
    list_view = ObjectProperty()
    def __init__(self, **kwargs):
        super(BuddyList, self).__init__(**kwargs)
        assert(self.list_view is not None)
        self.list_view.adapter.data = ['v1', 'v2']
    def roster_converter(self, index, txt):
        result = {
            "text": "%s %d" % (txt, index),
            'size_hint_y': None,
            'height': 25
        }
        return result
class TestForm(BoxLayout):
    text_input = ObjectProperty()

    def __init__(self, **kwargs):
        super(TestForm, self).__init__(**kwargs)
        self.buddy_list = BuddyList()
        self.add_widget(self.buddy_list)
class TestokApp(App):
    pass
if __name__ == '__main__':
    TestokApp().run()

$ cat testok.kv
#:import la kivy.adapters.listadapter
#:import ku kivy.uix.listview
TestForm:
<BuddyList>:
   list_view: list_view
    ListView:
        id: list_view
        adapter:
            la.ListAdapter(data=[], cls=ku.ListItemButton,
            args_converter=root.roster_converter)
<TestForm>:
    orientation: 'vertical'
    BoxLayout:
        Label:
            text: 'the label'

示例(mainko.py、testko.kv)崩溃:

$ cat mainko.py
from kivy.app import App
from kivy.properties import ObjectProperty
from kivy.uix.boxlayout import BoxLayout
class BuddyList(BoxLayout):
    list_view = ObjectProperty()
    def __init__(self, **kwargs):
        super(BuddyList, self).__init__(**kwargs)
        assert(self.list_view is not None)
        self.list_view.adapter.data = ['v1', 'v2']
    def roster_converter(self, index, txt):
        result = {
            "text": "%s %d" % (txt, index),
            'size_hint_y': None,
            'height': 25
        }
        return result
class TestForm(BoxLayout):
    text_input = ObjectProperty()
    def __init__(self, **kwargs):
        super(TestForm, self).__init__(**kwargs)
class TestkoApp(App):
    pass
if __name__ == '__main__':
    TestkoApp().run()

$ cat testko.kv
#:import la kivy.adapters.listadapter
#:import ku kivy.uix.listview
TestForm:
<BuddyList>:
    list_view: list_view
    ListView:
        id: list_view
        adapter:
            la.ListAdapter(data=[], cls=ku.ListItemButton,
            args_converter=root.roster_converter)
<TestForm>:
    orientation: 'vertical'
    BoxLayout:
        Label:
            text: 'the label'
    BuddyList:

崩溃并出现以下错误

  assert(self.list_view is not None)
     AssertionError

两者的区别是:

$ diff -u mainko.py ../ok/mainok.py
--- mainko.py       2013-10-23 14:11:26.976723764 +0200
+++ ../ok/mainok.py 2013-10-23 14:12:34.976841090 +0200
@@ -26,10 +26,13 @@

 def __init__(self, **kwargs):
     super(TestForm, self).__init__(**kwargs)
+        self.buddy_list = BuddyList()
+        self.add_widget(self.buddy_list)

-class TestkoApp(App):
+
+class TestokApp(App):
     pass

 if __name__ == '__main__':
-    TestkoApp().run()
+    TestokApp().run()

$ diff -u testko.kv ../ok/testok.kv
--- testko.kv       2013-10-23 14:10:11.948299722 +0200
+++ ../ok/testok.kv 2013-10-23 14:16:51.352688453 +0200
@@ -16,5 +16,4 @@
 BoxLayout:
     Label:
         text: 'the label'
-    BuddyList:

知道为什么第一个成功,第二个失败吗?

谢谢,

【问题讨论】:

    标签: kivy


    【解决方案1】:

    看起来问题是__init__ 方法实际上并没有完全解析和设置 kv 指令,尽管我不确定细节 - 我猜它在事件循环中安排了一些东西。当您尝试检查 self.list_view 时,您会得到 None,因为尚未设置。

    如果您使用时钟,您可以安排在到目前为止安排的所有其他事情之后(以及在完全执行 kv 指令之后)但在下一帧之前执行您的 post_init 内容。这是对你的 mainko.py 做这样的事情的修改。它似乎对我有用。

    from kivy.app import App 
    from kivy.properties import ObjectProperty 
    from kivy.uix.boxlayout import BoxLayout 
    from kivy.clock import Clock 
    
    class BuddyList(BoxLayout): 
        list_view = ObjectProperty() 
    
        def __init__(self, **kwargs): 
            super(BuddyList, self).__init__(**kwargs) 
            Clock.schedule_once(self.post_init, 0) 
    
        def post_init(self, *args): 
            assert self.list_view is not None 
            self.list_view.adapter.data = ['v1', 'v2'] 
    
        def roster_converter(self, index, txt): 
            result = { 
                "text": "%s %d" % (txt, index), 
                'size_hint_y': None, 
                'height': 25 
            } 
            return result 
    
    class TestForm(BoxLayout): 
        text_input = ObjectProperty() 
        def __init__(self, **kwargs): 
            super(TestForm, self).__init__(**kwargs) 
    
    
    class TestkoApp(App): 
        pass 
    
    
    if __name__ == '__main__': 
        TestkoApp().run() 
    

    【讨论】:

    • 谢谢,这也适用于我们。它是 kivy 中的错误还是功能 ;-)?
    • 我很确定这是故意的,如果你喜欢的话,这是一个“功能”,但是当我快速浏览时,我不明白为什么它会这样。可能其中一位开发人员会知道更多。
    • +1 给你们俩。我确信它是这样的!他们为什么不在文档中说明? kivy.org/docs/api-kivy.properties.html
    猜你喜欢
    • 1970-01-01
    • 2018-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-16
    相关资源
    最近更新 更多