python - 当窗口调整大小时,Kivy recycleview 项目会重新排序
问题描述
我使用 Kivy'srecycleview
以类似表格的方式显示数据列表。我使用文档中的示例作为实现的基础。
在我的程序中,RecycleDataView 基于 BoxLayout,其子小部件是动态生成的。
这似乎可行,但有时显示项目的顺序会颠倒,并且如果您调整窗口大小,则会不断变化。更糟糕的是,如果你向下滚动,布局会变得非常疯狂。如果我使用简单的标签作为项目类,则不会发生这种情况,所以我想问题出在我的动态创建的小部件逻辑上,但我不明白为什么。
这是一些显示问题的最小代码。
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)
当您运行应用程序时,您应该看到如果项目被颠倒并且出于某种原因以 10 而不是 100 开头的顺序。
在窗口的一个角落用鼠标调整窗口大小后,您应该会看到内容不断重新排序。
如果你向下滚动,事情会变得更加疯狂。
不幸的是,我不知道是什么导致了这种行为。我之前开发了一些 Kivy 应用程序,但这是我第一次真正深入研究,不仅仅使用标签和一些输入。
解决方案
这是对您的代码的修改,似乎可以正常工作:
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
. 线
self.create_widgets(data.pop('attribute', None))
被替换为
self.create_widgets(data['attribute'])
因为pop()
实际上删除了数据,我认为您不想这样做。
该类RV
现在有一个用于Label
小部件的缓存和另一个用于Button
小部件的缓存,并且它们被回收(类似于所做的事情RecycleView
。该create_widgets
方法删除所有子级RVItem
并将它们添加到缓存中,然后根据需要回收或创建小部件以填充出RVItem
.
我values
为某些数据添加了额外的项目,以帮助说明这是如何工作的。
推荐阅读
- python - 如何在使用 python igraph 创建的有向图中向边缘标签添加权重?
- angular - mat-menu 总是出现在页尾
- r - 基于日期范围的循环分配ID,如何提高代码效率?
- excel - 如何格式化电子邮件的正文
- number-systems - 大家好。我正在努力将二进制转换为十进制作为 8 位数字
- c++ - 线程指针向量,push_back 导致崩溃
- ios - 安排每小时重复本地通知的问题
- python - 尝试求解隐式方程时,UnboundLocalError '在赋值前引用'
- flutter - 将 onTap 函数传递给颤振中的另一个小部件
- sas - 我使用什么代码在 SAS 中创建 1-50 内的第一个素数?