【问题标题】:Is Kivy widgets creation really so slow or am I doing it wrong?Kivy 小部件的创建真的这么慢还是我做错了?
【发布时间】:2017-11-28 16:03:08
【问题描述】:

我注意到在我的应用中创建小部件的速度很慢,因此我创建了这个简单的测试应用来检查它。它包含两个屏幕,每个屏幕都包含简单的小部件列表。

应用:

from kivy.app import App
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty, StringProperty
from kivy.clock import Clock

from time import time

class ListScreen(Screen):

    items_box = ObjectProperty(None)

    def on_enter(self):
        start = time()
        for i in range(0,50):
            self.items_box.add_widget(ListItem('Item '+str(i)))
        self.items_box.bind(minimum_height=self.items_box.setter('height'))
        print time()-start

    def on_leave(self):
        self.items_box.clear_widgets()

class ListItem(BoxLayout):

    title = StringProperty('')

    def __init__(self, title, **kwargs):
        super(ListItem, self).__init__(**kwargs)
        self.title = title

class ListApp(App):

    sm = ScreenManager()
    screens = {}

    def build(self):
        self.__create_screens()
        ListApp.sm.add_widget(ListApp.screens['list1'])
        Clock.schedule_interval(self._switch, 1)
        return ListApp.sm

    def _switch(self, *args):
        ListApp.sm.switch_to(ListApp.screens['list1' if ListApp.sm.current != 'list1' else 'list2'])

    def __create_screens(self):
        ListApp.screens['list1'] = ListScreen(name='list1')
        ListApp.screens['list2'] = ListScreen(name='list2')

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

list.kv 文件:

<ListScreen>:
    items_box: items_box
    BoxLayout:
        orientation: "vertical"
        AnchorLayout:
            size_hint_y: 0.1
            padding: self.width*0.1, self.height*0.05
            Label:
                font_size: root.height*0.05
                text: "Some list"
        ScrollView:
            size_hint_y: 0.9
            size: self.size
            BoxLayout:
                id: items_box
                orientation: "vertical"
                padding: self.width*0.1, 0
                size_hint_y: None

<ListItem>:
    orientation: "horizontal"
    size_hint_y: None
    height: app.sm.height*0.1
    Label:
        font_size: app.sm.height*0.025
        text: root.title
        size_hint_x: 0.9
        text_size: self.size
        valign: "middle"
    CheckBox
        size_hint_x: 0.1

登录我的设备 (Moto G):

11-28 11:44:09.525  1848  2044 I python  : 0.5793800354
11-28 11:44:10.853  1848  2044 I python  : 0.453143119812
11-28 11:44:12.544  1848  2044 I python  : 0.633069992065
11-28 11:44:13.697  1848  2044 I python  : 0.369570970535
11-28 11:44:14.988  1848  2044 I python  : 0.594089031219
11-28 11:44:16.017  1848  2044 I python  : 0.339677095413
11-28 11:44:17.315  1848  2044 I python  : 0.58710193634
11-28 11:44:18.403  1848  2044 I python  : 0.359042882919
11-28 11:44:19.741  1848  2044 I python  : 0.613200187683
11-28 11:44:20.820  1848  2044 I python  : 0.359098911285
11-28 11:44:22.139  1848  2044 I python  : 0.60958814621
11-28 11:44:23.199  1848  2044 I python  : 0.354372024536
11-28 11:44:24.538  1848  2044 I python  : 0.643312931061
11-28 11:44:25.606  1848  2044 I python  : 0.360656023026
11-28 11:44:26.995  1848  2044 I python  : 0.682018995285
11-28 11:44:28.140  1848  2044 I python  : 0.393831014633
11-28 11:44:29.470  1848  2044 I python  : 0.591700077057
11-28 11:44:30.525  1848  2044 I python  : 0.346837043762
11-28 11:44:31.818  1848  2044 I python  : 0.607005834579
11-28 11:44:32.877  1848  2044 I python  : 0.36404299736
11-28 11:44:34.149  1848  2044 I python  : 0.586351156235
11-28 11:44:35.195  1848  2044 I python  : 0.349910974503
11-28 11:44:36.484  1848  2044 I python  : 0.588956832886
11-28 11:44:37.547  1848  2044 I python  : 0.367785930634
11-28 11:44:38.886  1848  2044 I python  : 0.639610052109
11-28 11:44:40.007  1848  2044 I python  : 0.394254922867
11-28 11:44:41.464  1848  2044 I python  : 0.732916116714

来吧,真的吗?创建带有标签和复选框的 50 行的简单列表平均需要 0.5 秒?还是我做错了什么?

【问题讨论】:

    标签: android python kivy


    【解决方案1】:

    感谢 Alexander Taylor(Kivy 开发人员之一)找到了解决方案。这是他的回答:

    小部件的创建速度相对较慢,尤其是取决于 小部件包含。

    如果列出大列表,例如您的示例,通常情况会更好 使用回收视图。这优化了事物以重用较少数量的 滚动期间的小部件。

    所以我试过了。

    应用:

    from kivy.app import App
    from kivy.uix.screenmanager import ScreenManager, Screen
    from kivy.properties import ObjectProperty
    from kivy.clock import Clock
    
    from time import time
    
    class ListScreen(Screen):
    
        recycle_view = ObjectProperty(None)
        items_box = ObjectProperty(None)
    
        def on_enter(self):
            start = time()
            for i in range(0,50):
                self.recycle_view.data.append({'title': 'item'+str(i)})
            print time()-start
    
        def on_leave(self):
            self.recycle_view.data = []
    
    class ListApp(App):
    
        sm = ScreenManager()
        screens = {}
    
        def build(self):
            self.__create_screens()
            ListApp.sm.add_widget(ListApp.screens['list1'])
            Clock.schedule_interval(self._switch, 1)
            return ListApp.sm
    
        def _switch(self, *args):
            ListApp.sm.switch_to(ListApp.screens['list1' if ListApp.sm.current != 'list1' else 'list2'])
    
        def __create_screens(self):
            ListApp.screens['list1'] = ListScreen(name='list1')
            ListApp.screens['list2'] = ListScreen(name='list2')
    
    if __name__ == '__main__':
        ListApp().run()
    

    list.kv 文件:

    <ListScreen>:
        recycle_view: recycle_view
        items_box: items_box
        BoxLayout:
            orientation: "vertical"
            AnchorLayout:
                size_hint_y: 0.1
                padding: self.width*0.1, self.height*0.05
                Label:
                    font_size: root.height*0.05
                    text: "Some list"
            RecycleView:
                id: recycle_view
                size_hint: 1, 0.9
                viewclass: "ListItem"
                RecycleBoxLayout:
                    id: items_box
                    orientation: "vertical"
                    padding: self.width*0.1, 0
                    default_size_hint: 1, None
                    size_hint: 1, None
                    height: self.minimum_height
    
    <ListItem@BoxLayout>:
        orientation: "horizontal"
        size_hint: 1, None
        height: app.sm.height*0.1
        title: ''
        Label:
            font_size: app.sm.height*0.025
            text: root.title
            size_hint_x: 0.9
            text_size: self.size
            valign: "middle"
        CheckBox
            size_hint_x: 0.1
    

    登录同一设备(Moto G):

    11-29 13:11:58.196 13121 13203 I python  : 0.00388479232788
    11-29 13:11:59.192 13121 13203 I python  : 0.00648307800293
    11-29 13:12:00.189 13121 13203 I python  : 0.00288391113281
    11-29 13:12:01.189 13121 13203 I python  : 0.00324606895447
    11-29 13:12:02.194 13121 13203 I python  : 0.00873804092407
    11-29 13:12:03.188 13121 13203 I python  : 0.00265002250671
    11-29 13:12:04.209 13121 13203 I python  : 0.00614500045776
    

    快 100 倍以上!太棒了。

    【讨论】:

    • 赞成,但是当视图在 RecycleView 中占用很大空间时,我真的不喜欢 RecycleView,只有第一个项目是在初始化时创建的,另一个是在您滚动到它们时创建的,这不是很高兴看到您的应用的用户
    • @SPSP 似乎 RecycleView 无法正常处理大小取决于内容的项目(例如带有height: self.texture_size[1] 的标签)。
    猜你喜欢
    • 1970-01-01
    • 2017-08-23
    • 1970-01-01
    • 1970-01-01
    • 2011-05-02
    • 2010-12-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多