Kivy的依赖性回收视图

时间:2018-05-24 17:04:18

标签: python-3.x kivy

我的问题:我想要两个RecycleViews,第二个(CultureSubView)依赖于第一个(CultureView)中点击的内容。
它可以用来调用"更新"只要单击CultureView中的某些内容,CultureSubView的功能,但我不知道如何做到这一点。

因为必须在SelectableLabel中完成(可能需要额外的SelectableLabel,因为CultureView不需要额外的功能)
或者在kivy语言的CultureView中。

我还尝试过找到任何可以触发" on_press"在CultureView中然后更新CultureSubView,但我也没有找到任何选项。这个想法在代码中被注释掉了。

from kivy.app import App
from kivy.properties import StringProperty, BooleanProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.scrollview import ScrollView


Builder.load_string('''
<ScreenCulture>:
    BoxLayout:
        orientation: 'vertical'

        Label:
            pos_hint: {"x": .45, "top": 1}
            text: "Testosterone"
            size_hint: .1, .1

        GridLayout:
            id: culture_layout
            rows: 1
            cols: 3
            padding: dp(10)
            spacing: dp(10)
            orientation: 'horizontal'

            CultureView:
                id: culture_list_view
                # on_press? culture_sub_view.update()

            CultureSubView:
                id: culture_sub_view
                name_selected: 
                    "Planet" if not culture_list_view.name_selected else culture_list_view.name_selected

            CultureLabel:
                id: culture_text
                name_selected: "NVM" if not culture_sub_view.name_selected else culture_sub_view.name_selected
                text_selected: "This is totally a test text" if not culture_sub_view.text_selected else culture_sub_view.text_selected


<CultureView>:
    viewclass: 'SelectableLabel'
    name_selected: ''

    SelectableRecycleBoxLayout:
        orientation: 'vertical' 
        default_size: None, dp(32)
        default_size_hint: .6, None
        size_hint: 1, .9
        multiselect: False
        touch_multiselect: False


<CultureSubView>:
    viewclass: 'SelectableLabel'
    text_selected: ''
    name_selected: ''

    SelectableRecycleBoxLayout:
        orientation: 'vertical' 
        default_size: None, dp(32)
        default_size_hint: .6, None
        size_hint: 1, .9
        multiselect: False
        touch_multiselect: False


<CultureLabel>:
    size_hint_y: .85
    Label:
        halign: 'left'
        valign: 'middle'
        size_hint_y: None
        height: self.texture_size[1]
        text_size: self.width, None
        text: root.text_selected


<SelectableLabel>:
    # Draw a background to indicate selection
    canvas.before:
        Color:
            rgba: (.05, 0.5, .9, .8) if self.selected else (.5, .5, .5, 1)
        Rectangle:
            pos: self.pos
            size: self.size
''')


class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                                 RecycleBoxLayout):
    pass


class SelectableLabel(RecycleDataViewBehavior, Label):
    ''' Add selection support to the Label '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        return super(SelectableLabel, self).refresh_view_attrs(
            rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableLabel, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):
        ''' Respond to the selection of items in the view. '''
        self.selected = is_selected
        if is_selected:
            print("selection changed to {0}".format(rv.data[index]))
            rv.name_selected = rv.data[index]['text']
        else:
            print("selection removed for {0}".format(rv.data[index]))


class CultureView(RecycleView):
    def __init__(self, **kwargs):
        super(CultureView, self).__init__(**kwargs)

        self.data = [
            {"text": "Test1", "description": "testu"},
            {"text": "Test2", "description": "testo"}
        ]


class CultureSubView(RecycleView):
    planet_selected = StringProperty('')

    def __init__(self, **kwargs):
        super(CultureSubView, self).__init__(**kwargs)
        self.selection_data = {
            '': [],
            'Test1': [
                {"text": "test1.1", "description": "test1"},
                {"text": "test1.2", "description": "text1"}
            ],
            'Test2': [
                {"text": "test2.1", "description": "text2"},
                {"text": "test2.2", "description": "test2"}
            ]
        }
        self.data = self.selection_data[self.planet_selected]

    def update(self):
        print("Updating")
        self.data = self.selection_data[self.planet_selected]
        self.refresh_from_data()


class CultureLabel(ScrollView):
    text_selected = StringProperty('')
    name_selected = StringProperty('')


class ScreenCulture(Screen):
    pass


screen_manager = ScreenManager()
screen_manager.add_widget(ScreenCulture(name="screen_culture"))

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


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

一如既往,感谢您的帮助:)

1 个答案:

答案 0 :(得分:1)

由于该项目是 SelectableLabel ,请使用 on_touch_down 事件来调用方法 CultureSubView.update()

调用方法 CultureSubView.update()有两个选项,一个选项来自kv文件,另一个来自Python脚本。这两个选项都使用了Kivy ObjectProperty。添加 ObjectProperty 以连接 culture_sub_view ScreenManager ScreenCulture 。有关详细信息,请参阅示例。

选项1 - 通过kv文件调用 CultureSubView.update()

在此选项中, on_touch_down 事件被调用两次,因为我们有一个类SelectableLabel,它在两个地方使用,即CultureView和CultureSubView。

片段

kv文件

Builder.load_string('''
<ScreenManagement>:
    screen_culture: screen_culture

    ScreenCulture:
        id: screen_culture
        name: 'screen_culture'

<ScreenCulture>:
    culture_sub_view: culture_sub_view

...

<SelectableLabel>:
    # Draw a background to indicate selection
    canvas.before:
        Color:
            rgba: (.05, 0.5, .9, .8) if self.selected else (.5, .5, .5, 1)
        Rectangle:
            pos: self.pos
            size: self.size
    on_touch_down:
        print('on_touch_down:')
        if self.selectable: \
            app.root.screen_culture.culture_sub_view.update(self.text)

Python脚本

class SelectableLabel(RecycleDataViewBehavior, Label):
    ...

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableLabel, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)
...

class ScreenCulture(Screen):
    culture_sub_view = ObjectProperty(None)


class ScreenManagement(ScreenManager):
    screen_culture = ObjectProperty(None)


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

选项2 - 通过Python脚本

调用 CultureSubView.update()

在此选项中,我们使用 App.get_running_app()。root.screen_culture.culture_sub_view.update()调用该方法,并将 self.text 传递给它。< / p>

片段

kv文件

Builder.load_string('''
<ScreenManagement>:
    screen_culture: screen_culture

    ScreenCulture:
        id: screen_culture
        name: 'screen_culture'

<ScreenCulture>:
    culture_sub_view: culture_sub_view

Python脚本

class SelectableLabel(RecycleDataViewBehavior, Label):
    ...

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableLabel, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            App.get_running_app().root.screen_culture.culture_sub_view.update(self.text)
            return self.parent.select_with_touch(self.index, touch)
...

class ScreenCulture(Screen):
    culture_sub_view = ObjectProperty(None)


class ScreenManagement(ScreenManager):
    screen_culture = ObjectProperty(None)


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

实施例

选项1 - 通过kv文件调用 CultureSubView.update()

from kivy.app import App
from kivy.properties import StringProperty, BooleanProperty, ObjectProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.scrollview import ScrollView

Builder.load_string('''
<ScreenManagement>:
    screen_culture: screen_culture

    ScreenCulture:
        id: screen_culture
        name: 'screen_culture'

<ScreenCulture>:
    culture_sub_view: culture_sub_view

    BoxLayout:
        orientation: 'vertical'

        Label:
            pos_hint: {"x": .45, "top": 1}
            text: "Testosterone"
            size_hint: .1, .1

        GridLayout:
            id: culture_layout
            rows: 1
            cols: 3
            padding: dp(10)
            spacing: dp(10)
            orientation: 'horizontal'

            CultureView:
                id: culture_list_view

            CultureSubView:
                id: culture_sub_view
                name_selected: 
                    "Planet" if not culture_list_view.name_selected else culture_list_view.name_selected

            CultureLabel:
                id: culture_text
                name_selected: 
                    "NVM" if not culture_sub_view.name_selected else culture_sub_view.name_selected

                text_selected: 
                    "This is totally a test text" if not culture_sub_view.text_selected else culture_sub_view.text_selected


<CultureView>:
    viewclass: 'SelectableLabel'
    name_selected: ''

    SelectableRecycleBoxLayout:
        orientation: 'vertical' 
        default_size: None, dp(32)
        default_size_hint: .6, None
        size_hint: 1, .9
        multiselect: False
        touch_multiselect: False


<CultureSubView>:
    viewclass: 'SelectableLabel'
    text_selected: ''
    name_selected: ''

    SelectableRecycleBoxLayout:
        orientation: 'vertical' 
        default_size: None, dp(32)
        default_size_hint: .6, None
        size_hint: 1, .9
        multiselect: False
        touch_multiselect: False


<CultureLabel>:
    size_hint_y: .85
    Label:
        halign: 'left'
        valign: 'middle'
        size_hint_y: None
        height: self.texture_size[1]
        text_size: self.width, None
        text: root.text_selected


<SelectableLabel>:
    # Draw a background to indicate selection
    canvas.before:
        Color:
            rgba: (.05, 0.5, .9, .8) if self.selected else (.5, .5, .5, 1)
        Rectangle:
            pos: self.pos
            size: self.size
    on_touch_down:
        print('on_touch_down:')
        if self.selectable: \
            app.root.screen_culture.culture_sub_view.update(self.text)
''')


class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                                 RecycleBoxLayout):
    pass


class SelectableLabel(RecycleDataViewBehavior, Label):
    ''' Add selection support to the Label '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        return super(SelectableLabel, self).refresh_view_attrs(
            rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableLabel, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):
        ''' Respond to the selection of items in the view. '''
        self.selected = is_selected
        if is_selected:
            print("selection changed to {0}".format(rv.data[index]))
            rv.name_selected = rv.data[index]['text']
        else:
            print("selection removed for {0}".format(rv.data[index]))


class CultureView(RecycleView):
    def __init__(self, **kwargs):
        super(CultureView, self).__init__(**kwargs)

        self.data = [
            {"text": "Test1", "description": "testu"},
            {"text": "Test2", "description": "testo"}
        ]


class CultureSubView(RecycleView):
    planet_selected = StringProperty('')

    def __init__(self, **kwargs):
        super(CultureSubView, self).__init__(**kwargs)
        self.selection_data = {
            '': [],
            'Test1': [
                {"text": "test1.1", "description": "test1"},
                {"text": "test1.2", "description": "text1"}
            ],
            'Test2': [
                {"text": "test2.1", "description": "text2"},
                {"text": "test2.2", "description": "test2"}
            ]
        }
        self.data = self.selection_data[self.planet_selected]

    def update(self, name_selected):
        print("Updating")
        self.planet_selected = name_selected
        self.data = self.selection_data[self.planet_selected]
        self.refresh_from_data()


class CultureLabel(ScrollView):
    text_selected = StringProperty('')
    name_selected = StringProperty('')


class ScreenCulture(Screen):
    culture_sub_view = ObjectProperty(None)


class ScreenManagement(ScreenManager):
    screen_culture = ObjectProperty(None)


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


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

选项2 - 通过Python脚本调用 CultureSubView.update()

from kivy.app import App
from kivy.properties import StringProperty, BooleanProperty, ObjectProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.scrollview import ScrollView


Builder.load_string('''
<ScreenManagement>:
    screen_culture: screen_culture

    ScreenCulture:
        id: screen_culture
        name: 'screen_culture'

<ScreenCulture>:
    culture_sub_view: culture_sub_view

    BoxLayout:
        orientation: 'vertical'

        Label:
            pos_hint: {"x": .45, "top": 1}
            text: "Testosterone"
            size_hint: .1, .1

        GridLayout:
            id: culture_layout
            rows: 1
            cols: 3
            padding: dp(10)
            spacing: dp(10)
            orientation: 'horizontal'

            CultureView:
                id: culture_list_view

            CultureSubView:
                id: culture_sub_view
                name_selected: 
                    "Planet" if not culture_list_view.name_selected else culture_list_view.name_selected

            CultureLabel:
                id: culture_text
                name_selected: 
                    "NVM" if not culture_sub_view.name_selected else culture_sub_view.name_selected

                text_selected: 
                    "This is totally a test text" if not culture_sub_view.text_selected else culture_sub_view.text_selected


<CultureView>:
    viewclass: 'SelectableLabel'
    name_selected: ''

    SelectableRecycleBoxLayout:
        orientation: 'vertical' 
        default_size: None, dp(32)
        default_size_hint: .6, None
        size_hint: 1, .9
        multiselect: False
        touch_multiselect: False


<CultureSubView>:
    viewclass: 'SelectableLabel'
    text_selected: ''
    name_selected: ''

    SelectableRecycleBoxLayout:
        orientation: 'vertical' 
        default_size: None, dp(32)
        default_size_hint: .6, None
        size_hint: 1, .9
        multiselect: False
        touch_multiselect: False


<CultureLabel>:
    size_hint_y: .85
    Label:
        halign: 'left'
        valign: 'middle'
        size_hint_y: None
        height: self.texture_size[1]
        text_size: self.width, None
        text: root.text_selected


<SelectableLabel>:
    # Draw a background to indicate selection
    canvas.before:
        Color:
            rgba: (.05, 0.5, .9, .8) if self.selected else (.5, .5, .5, 1)
        Rectangle:
            pos: self.pos
            size: self.size
''')


class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                                 RecycleBoxLayout):
    pass


class SelectableLabel(RecycleDataViewBehavior, Label):
    ''' Add selection support to the Label '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        return super(SelectableLabel, self).refresh_view_attrs(
            rv, index, data)

    def on_touch_down(self, touch):
        ''' Add selection on touch down '''
        if super(SelectableLabel, self).on_touch_down(touch):
            return True
        if self.collide_point(*touch.pos) and self.selectable:
            App.get_running_app().root.screen_culture.culture_sub_view.update(self.text)
            return self.parent.select_with_touch(self.index, touch)

    def apply_selection(self, rv, index, is_selected):
        ''' Respond to the selection of items in the view. '''
        self.selected = is_selected
        if is_selected:
            print("selection changed to {0}".format(rv.data[index]))
            rv.name_selected = rv.data[index]['text']
        else:
            print("selection removed for {0}".format(rv.data[index]))


class CultureView(RecycleView):
    def __init__(self, **kwargs):
        super(CultureView, self).__init__(**kwargs)

        self.data = [
            {"text": "Test1", "description": "testu"},
            {"text": "Test2", "description": "testo"}
        ]


class CultureSubView(RecycleView):
    planet_selected = StringProperty('')

    def __init__(self, **kwargs):
        super(CultureSubView, self).__init__(**kwargs)
        self.selection_data = {
            '': [],
            'Test1': [
                {"text": "test1.1", "description": "test1"},
                {"text": "test1.2", "description": "text1"}
            ],
            'Test2': [
                {"text": "test2.1", "description": "text2"},
                {"text": "test2.2", "description": "test2"}
            ]
        }
        self.data = self.selection_data[self.planet_selected]

    def update(self, name_selected):
        print("Updating")
        self.planet_selected = name_selected
        self.data = self.selection_data[self.planet_selected]
        self.refresh_from_data()


class CultureLabel(ScrollView):
    text_selected = StringProperty('')
    name_selected = StringProperty('')


class ScreenCulture(Screen):
    culture_sub_view = ObjectProperty(None)


class ScreenManagement(ScreenManager):
    screen_culture = ObjectProperty(None)


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


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

输出:选项1 - 通过kv文件调用 CultureSubView.update()

Img01 - Clicked on Test1 Img02 - Clicked on Test2

输出:选项2 - 通过Python脚本调用 CultureSubView.update()

Img03 - Clicked on Test1 Img04 - Clicked on Test2