【问题标题】:Having issues with Kivy RecycleView dataKivy RecycleView 数据存在问题
【发布时间】:2021-12-01 19:34:10
【问题描述】:

我在使用 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

感谢您的帮助,谢谢!

【问题讨论】:

    标签: python kivy kivy-language


    【解决方案1】:

    RecycleView 的工作原理是创建viewclass 的实例(代码中的Post),然后从data 字典中分配值。因此,Post 类的 __init__() 方法会创建它们的子类并传入 namedatetime 的当前值。但这些值仍然是当时'' 的默认值。然后,当namedatetime 的实际值被设置为Post 实例时,为时已晚,并且这些值不会传递给Post 实例的子代。

    解决此问题的一种方法是使用 kivy 语言,因为它会自动绑定到 StringProperty 变量。因此,您可以扩展您的 main.kv 以包含 Post 类及其子类:

    <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 使用 StringProperty 类的 StringProperty 值,因此它们会自动更新。

    那么Post类可以更简单地定义:

    class Post(AnchorLayout):
        date = StringProperty('')
        time = StringProperty('')
        name = StringProperty('')
    
    
    class PostContainer(GridLayout):
        pass
    
    
    class PostShellOne(GridLayout):
        pass
    
    
    class PostShellTwo(Button):
        pass
    

    【讨论】:

    • 好的,这解决了问题,非常感谢您的帮助!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-09-17
    • 2021-10-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多