Kivy RecycleView 数据有问题
Having issues with Kivy RecycleView data
我在使用 Kivy 的 RecycleView 时遇到一个奇怪的问题。当尝试使用我作为视图类制作的自定义小部件传递字典列表时,它似乎创建了正确数量的小部件,但是实际值似乎没有通过,导致正确数量的“默认”小部件。这是我针对遇到的问题创建的可运行示例:
main.py:
from kivy.app import App
import view
class MainApp(App):
def build(self):
return view.PostRV()
if __name__ == '__main__':
app = MainApp()
app.run()
main.kv:
<RVContainer>:
multiselect: True
touch_multiselect: True
height: self.minimum_height
cols: 1
default_size_hint: 1, None
default_size: None, dp(110)
size_hint_y: None
view.py:
from kivy.uix.recycleview import RecycleView
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.graphics import Color, RoundedRectangle
from kivy.core.window import Window
from kivy.properties import StringProperty
from kivy.uix.recyclegridlayout import RecycleGridLayout
class PostRV(RecycleView):
def __init__(self, **var_args):
super(PostRV, self).__init__(**var_args)
self.data = [
{'date': 'a date', 'time': 'a time', 'name': 'a name'},
{'date': 'another date', 'time': 'another time', 'name': 'another name'}
] # this data does not seem to pass through properly
self.add_widget(RVContainer())
self.size_hint = 1, 1
self.viewclass = Post
class RVContainer(RecycleGridLayout):
pass
# below this line is the custom widget "Post" which I split into multiple classes for easier control and clarity
class Post(AnchorLayout):
date = StringProperty('')
time = StringProperty('')
name = StringProperty('')
def __init__(self, **var_args):
super(Post, self).__init__(**var_args)
self.anchor_y = 'center'
self.anchor_x = 'center'
self.size_hint = 1, None
self.height = '110dp'
self.add_widget(PostContainer(date=self.date, time=self.time, name=self.name))
class PostContainer(GridLayout):
date = StringProperty('')
time = StringProperty('')
name = StringProperty('')
def __init__(self, **var_args):
super(PostContainer, self).__init__(**var_args)
self.cols = 2
self.padding = '12dp'
self.size_hint = (None, None)
self.width = Window.size[0] / 1.05
self.height = '100dp'
self.add_widget(PostShellOne(date=self.date, time=self.time, name=self.name))
self.add_widget(PostShellTwo())
self.bind(pos=self.update_rect, size=self.update_rect)
with self.canvas.before:
Color(1, 1, 1, .7)
self.rect = RoundedRectangle(size=self.size, pos=self.pos, radius=[10])
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
self.width = Window.size[0] / 1.05
class PostShellOne(GridLayout):
date = StringProperty('')
time = StringProperty('')
name = StringProperty('')
def __init__(self, **var_args):
super(PostShellOne, self).__init__(**var_args)
self.rows = 3
name_label = Label(text=self.name, color=(0, 0, 0, 1))
date_label = Label(text=self.date, color=(0, 0, 0, 1))
time_label = Label(text=self.time, color=(0, 0, 0, 1))
self.add_widget(name_label)
self.add_widget(time_label)
self.add_widget(date_label)
class PostShellTwo(Button):
def __init__(self, **var_args):
super(PostShellTwo, self).__init__(**var_args)
self.text = 'button'
self.background_color = (0, 0, 0, 0)
self.background_normal = ''
self.bind(pos=self.update_rect, size=self.update_rect)
with self.canvas.before:
Color(0, 0, 0, .4)
self.rect = RoundedRectangle(size=self.size, pos=self.pos, radius=[40])
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
感谢任何帮助,谢谢!
RecycleView
的工作原理是创建 viewclass
(代码中的 Post
)的实例,然后从 data
字典中分配值。因此,Post
classes 的 __init__()
方法会创建它们的 child classes 并传入 name
、[=19] 的当前值=],以及 time
。但是那些值仍然是''
当时的默认值。然后,当为 Post
实例设置 name
、date
和 time
的实际值时,为时已晚,并且这些值不会传递给 children Post
实例。
解决这个问题的一种方法是使用 kivy 语言,因为它会自动绑定到 StringProperty
变量。因此,您可以扩展 main.kv
以包含 Post
class 及其 children:
<RVContainer>:
multiselect: True
touch_multiselect: True
height: self.minimum_height
cols: 1
default_size_hint: 1, None
default_size: None, dp(110)
size_hint_y: None
<Post>:
anchor_y: 'center'
anchor_x: 'center'
size_hint: 1, None
height: '110dp'
PostContainer:
cols: 2
padding: '12dp'
size_hint: (None, None)
width: app.root.size[0] / 1.05
height: '100dp'
canvas:
Color:
rgba: (1, 1, 1, .7)
RoundedRectangle:
size: self.size
pos: self.pos
radius: [10]
PostShellOne:
rows: 3
Label:
text: root.name
color: 0,0,0,1
Label:
text: root.date
color: 0,0,0,1
Label:
text: root.time
color: 0,0,0,1
PostShellTwo:
text: 'button'
background_color: (0, 0, 0, 0)
background_normal: ''
canvas.before:
Color:
rgba: (0, 0, 0, .4)
RoundedRectangle:
size: self.size
pos: self.pos
radius: [40]
请注意 PostShellOne
中的 Labels
使用 Post
class 的 StringProperty
值,因此它们会自动更新。
那么Post
classes可以更简单的定义:
class Post(AnchorLayout):
date = StringProperty('')
time = StringProperty('')
name = StringProperty('')
class PostContainer(GridLayout):
pass
class PostShellOne(GridLayout):
pass
class PostShellTwo(Button):
pass
我在使用 Kivy 的 RecycleView 时遇到一个奇怪的问题。当尝试使用我作为视图类制作的自定义小部件传递字典列表时,它似乎创建了正确数量的小部件,但是实际值似乎没有通过,导致正确数量的“默认”小部件。这是我针对遇到的问题创建的可运行示例:
main.py:
from kivy.app import App
import view
class MainApp(App):
def build(self):
return view.PostRV()
if __name__ == '__main__':
app = MainApp()
app.run()
main.kv:
<RVContainer>:
multiselect: True
touch_multiselect: True
height: self.minimum_height
cols: 1
default_size_hint: 1, None
default_size: None, dp(110)
size_hint_y: None
view.py:
from kivy.uix.recycleview import RecycleView
from kivy.uix.label import Label
from kivy.uix.button import Button
from kivy.uix.anchorlayout import AnchorLayout
from kivy.uix.gridlayout import GridLayout
from kivy.graphics import Color, RoundedRectangle
from kivy.core.window import Window
from kivy.properties import StringProperty
from kivy.uix.recyclegridlayout import RecycleGridLayout
class PostRV(RecycleView):
def __init__(self, **var_args):
super(PostRV, self).__init__(**var_args)
self.data = [
{'date': 'a date', 'time': 'a time', 'name': 'a name'},
{'date': 'another date', 'time': 'another time', 'name': 'another name'}
] # this data does not seem to pass through properly
self.add_widget(RVContainer())
self.size_hint = 1, 1
self.viewclass = Post
class RVContainer(RecycleGridLayout):
pass
# below this line is the custom widget "Post" which I split into multiple classes for easier control and clarity
class Post(AnchorLayout):
date = StringProperty('')
time = StringProperty('')
name = StringProperty('')
def __init__(self, **var_args):
super(Post, self).__init__(**var_args)
self.anchor_y = 'center'
self.anchor_x = 'center'
self.size_hint = 1, None
self.height = '110dp'
self.add_widget(PostContainer(date=self.date, time=self.time, name=self.name))
class PostContainer(GridLayout):
date = StringProperty('')
time = StringProperty('')
name = StringProperty('')
def __init__(self, **var_args):
super(PostContainer, self).__init__(**var_args)
self.cols = 2
self.padding = '12dp'
self.size_hint = (None, None)
self.width = Window.size[0] / 1.05
self.height = '100dp'
self.add_widget(PostShellOne(date=self.date, time=self.time, name=self.name))
self.add_widget(PostShellTwo())
self.bind(pos=self.update_rect, size=self.update_rect)
with self.canvas.before:
Color(1, 1, 1, .7)
self.rect = RoundedRectangle(size=self.size, pos=self.pos, radius=[10])
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
self.width = Window.size[0] / 1.05
class PostShellOne(GridLayout):
date = StringProperty('')
time = StringProperty('')
name = StringProperty('')
def __init__(self, **var_args):
super(PostShellOne, self).__init__(**var_args)
self.rows = 3
name_label = Label(text=self.name, color=(0, 0, 0, 1))
date_label = Label(text=self.date, color=(0, 0, 0, 1))
time_label = Label(text=self.time, color=(0, 0, 0, 1))
self.add_widget(name_label)
self.add_widget(time_label)
self.add_widget(date_label)
class PostShellTwo(Button):
def __init__(self, **var_args):
super(PostShellTwo, self).__init__(**var_args)
self.text = 'button'
self.background_color = (0, 0, 0, 0)
self.background_normal = ''
self.bind(pos=self.update_rect, size=self.update_rect)
with self.canvas.before:
Color(0, 0, 0, .4)
self.rect = RoundedRectangle(size=self.size, pos=self.pos, radius=[40])
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
感谢任何帮助,谢谢!
RecycleView
的工作原理是创建 viewclass
(代码中的 Post
)的实例,然后从 data
字典中分配值。因此,Post
classes 的 __init__()
方法会创建它们的 child classes 并传入 name
、[=19] 的当前值=],以及 time
。但是那些值仍然是''
当时的默认值。然后,当为 Post
实例设置 name
、date
和 time
的实际值时,为时已晚,并且这些值不会传递给 children Post
实例。
解决这个问题的一种方法是使用 kivy 语言,因为它会自动绑定到 StringProperty
变量。因此,您可以扩展 main.kv
以包含 Post
class 及其 children:
<RVContainer>:
multiselect: True
touch_multiselect: True
height: self.minimum_height
cols: 1
default_size_hint: 1, None
default_size: None, dp(110)
size_hint_y: None
<Post>:
anchor_y: 'center'
anchor_x: 'center'
size_hint: 1, None
height: '110dp'
PostContainer:
cols: 2
padding: '12dp'
size_hint: (None, None)
width: app.root.size[0] / 1.05
height: '100dp'
canvas:
Color:
rgba: (1, 1, 1, .7)
RoundedRectangle:
size: self.size
pos: self.pos
radius: [10]
PostShellOne:
rows: 3
Label:
text: root.name
color: 0,0,0,1
Label:
text: root.date
color: 0,0,0,1
Label:
text: root.time
color: 0,0,0,1
PostShellTwo:
text: 'button'
background_color: (0, 0, 0, 0)
background_normal: ''
canvas.before:
Color:
rgba: (0, 0, 0, .4)
RoundedRectangle:
size: self.size
pos: self.pos
radius: [40]
请注意 PostShellOne
中的 Labels
使用 Post
class 的 StringProperty
值,因此它们会自动更新。
那么Post
classes可以更简单的定义:
class Post(AnchorLayout):
date = StringProperty('')
time = StringProperty('')
name = StringProperty('')
class PostContainer(GridLayout):
pass
class PostShellOne(GridLayout):
pass
class PostShellTwo(Button):
pass