调整窗口大小时,对Kivy recycleview项目进行重新排序 [英] Kivy recycleview items get reordered when window gets resized

查看:51
本文介绍了调整窗口大小时,对Kivy recycleview项目进行重新排序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我使用Kivy的recycleview以类似表格的方式显示数据列表.我使用了文档中的示例作为我实施的基础.

I use Kivy's recycleview to show a list of data in a table like manner. I used the example from the docs as a base for my implementation.

在我的程序中,RecycleDataView基于BoxLayout,并且其子窗口小部件是动态生成的.

In my program the RecycleDataView is based on a BoxLayout and its child widgets are generated dynamically.

这似乎可行,但是如果调整窗口大小,有时显示项目的顺序会颠倒,并且会不断变化.更糟糕的是,如果向下滚动,则布局将变得完全疯狂.如果我将简单的标签用作项目类,则不会发生这种情况,因此我想问题出在我动态创建的小部件逻辑上,但我不明白为什么.

This seems to work but the order in which the items are displayed is sometimes reversed and keeps changing if your resize the window. Even worse, if you scroll down, the layout gets completely crazy. This does not happen if I would use a simple label as item class, so I guess the problem is with my dynamicaly created widget logic but I don't understand why.

下面是显示问题的最少代码.

Here is some minimal code that shows the issue.

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty

Builder.load_string('''

<RV>:
    viewclass: 'RVItem'
    RecycleBoxLayout:
        default_size: None, dp(56)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'

''')

class Attribute:
    def __init__(self, name, values):
        self.name = name
        self.values = values


class RVItem(RecycleDataViewBehavior, BoxLayout):
    index = None
    attribute = ObjectProperty()

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        self.create_widgets(data.pop('attribute', None))
        return super(RVItem, self).refresh_view_attrs(
            rv, index, data)

    def create_widgets(self, value: Attribute):
        """Dynamically create the needed Widgets"""

        if value is None:
            return
        self.add_widget(Label(text=value.name, height=self.height, size_hint=(1, None)))

        if not isinstance(value.values, dict):
            self.add_widget(Label(text=value.values, height=self.height, size_hint=(1, None)))
        else:
            for _, v in value.values.items():
                self.add_widget(Label(text=v, height=self.height, size_hint=(1, None)))

        image_button = Button(text='+')
        #image_button.source = 'wm_ui/glyphs/plus.png'
        image_button.size_hint = None, None
        image_button.size = "30sp", "30sp"
        image_button.bind(on_press=self.add_button_pressed)
        self.add_widget(image_button)

    def add_button_pressed(self, s):
        print("Would add a new item to the recycleview if implemented.")


class RV(RecycleView):
    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.data = [{'attribute': Attribute(str(x), "test")} for x in range(100)]


class TestApp(App):
    def build(self):
        return RV()

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

为简单起见,我将一些小部件更改为它们的基类(例如ImageButton和Label)

I changed some Widgets to their base classes for simplicity (like ImageButton and Label)

运行该应用程序时,您应该会看到,如果由于某些原因,这些项是相反的,则顺序为10,而不是100.

When you run the application you should see that the order if the items is reversed and starting with 10 instead of 100 for some reason.

用鼠标在窗口的一个角上调整窗口大小后,您应该会看到内容在不断重新排序.

After resizing the window with the mouse in one of the window's corners you should see the contents continuously reordering.

如果向下滚动,事情会变得更加疯狂.

And if you scroll down, things get even more crazy.

不幸的是,我不知道是什么原因导致了这种现象.我之前曾开发过一些Kivy应用程序,但这是我第一次真正的深入研究,它不仅使用标签和一些输入内容.

Unfortunately I have no idea what causes the behavior. I developed some Kivy apps before but this is my first really deep dive that uses more than just labels and a few inputs.

推荐答案

这是对您的代码的修改,似乎可以正常工作:

Here is a modification of your code that seems to work correctly:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ObjectProperty

Builder.load_string('''

<RV>:
    viewclass: 'RVItem'
    RecycleBoxLayout:
        default_size: None, dp(56)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'

''')

class Attribute:
    def __init__(self, name, values):
        self.name = name
        self.values = values


class RVItem(RecycleDataViewBehavior, BoxLayout):
    index = None
    attribute = ObjectProperty()

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        self.create_widgets(data['attribute'])
        return super(RVItem, self).refresh_view_attrs(
            rv, index, data)

    def create_widgets(self, value: Attribute):
        rv = App.get_running_app().root
        rv.cache_widgets(self.children)
        self.clear_widgets()
        label = rv.get_label()
        label.text = value.name
        self.add_widget(label)
        if isinstance(value.values, dict):
            for _,v in value.values.items():
                label = rv.get_label()
                label.text = v
                self.add_widget(label)
        else:
            label = rv.get_label()
            label.text = value.values
            self.add_widget(label)
        image_button = rv.get_button()
        image_button.text = '+'
        image_button.size_hint = None, None
        image_button.size = "30sp", "30sp"
        image_button.bind(on_press=self.add_button_pressed)
        self.add_widget(image_button)


    def add_button_pressed(self, s):
        print("Would add a new item to the recycleview if implemented.")


class RV(RecycleView):
    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.label_cache = []
        self.button_cache = []
        self.data = [{'attribute': Attribute(str(x), "test")} for x in range(100)]
        for i in range(100):
            if i % 5 == 0:
                self.data[i]['attribute'].values = {'1': 'test1', '2': 'test2', '3': 'test3'}

    def get_button(self):
        if len(self.button_cache) > 0:
            return self.button_cache.pop()
        else:
            return Button()

    def get_label(self):
        if len(self.label_cache) > 0:
            return self.label_cache.pop()
        else:
            return Label()

    def cache_widgets(self, widgets):
        for w in widgets:
            if isinstance(w, Button):
                self.button_cache.append(w)
            else:
                self.label_cache.append(w)


class TestApp(App):
    def build(self):
        return RV()

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

在此版本中,refresh_view_attrs方法始终设置RVItem的所有属性.线

In this version, the refresh_view_attrs method always sets all the attributes of the RVItem. The line

self.create_widgets(data.pop('attribute', None))

被替换为

self.create_widgets(data['attribute'])

因为pop()实际上会删除数据,我认为您不想这样做.

because the pop() actually removes data, which I don't think you want to do.

RV类现在为Label小部件提供了一个缓存,为Button小部件提供了另一个,并对其进行回收(类似于RecycleView的操作.create_widgets方法删除了所有子元素). RVItem并将它们添加到缓存中,然后根据需要回收或创建小部件以填充RVItem.

The RV class now has a cache for Label widgets and another for Button widgets, and they get recycled (similar to what the RecycleView does. The create_widgets method removes all the children of the RVItem and adds them to the cache, then recycles or creates widgets, as needed, to fill out the RVItem.

我为values字典添加了一些数据项,以帮助说明其工作原理.

I have added additional items to the values dict for some of the data, to help illustrate how this works.

这篇关于调整窗口大小时,对Kivy recycleview项目进行重新排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆