[Kivy] RecycleViewの複数の項目を選択・取得する。

RecycleViewの項目を複数選択する

 RecycleViewでは複数の項目(ノード)を選択可能であり、複数選択した項目のデータを取得することができます。今回は、RecycleViewで複数項目の選択・選択データの取得をおこなう方法を紹介します。

RecycleViewで複数の項目を選択可能にする

 RecycleViewで複数の項目を選択可能にするには、multiselectとtouch_multiselectの値にTrueと指定します。

 multiselect:  複数の項目を選択できるかどうかを指定する。
 touch_multiselect: 複数の項目をタッチするだけで選択できるよにする。

        RecycleView:
            id: rv
            viewclass: 'RVBox'
            SelectableRecycleBoxLayout:
                id: selectablervl
                default_size: None, None
                size_hint: 1, None
                height: self.minimum_height
                orientation: 'vertical'
                multiselect: True
                touch_multiselect: True    

Recycleviewで選択した項目を取得する

 RecycleViewでは選択した項目の番号は、selected_nodesにリスト形式で保存されます。そのため、複数の項目を選択可能な場合は、以下のようにして、選択中の項目の番号を取得します。また、その番号を使用して、self.ids.rv.dataよりそのデータを得ることができます。


    def on_button_press(self):
        select_index = self.ids.selectablervl.selected_nodes
        for index in select_index:
            print(f"{index}: {self.ids.rv.data[index]}")

サンプルプログラム

 以下のサンプルプログラムは、実行すると左図のようなRecycleViewとその下にボタンが配置された画面が表示されます。RecycleView上の項目はマウスでクリックすることで選択でき、複数選択することが可能です。選択したデータの背景は、右図のように青色になります。
 また、データを選択した状態でボタンを押すと、ターミナルに選択中の項目をすべて出力します。

# -*- coding: utf-8 -*-

import kivy

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.config import Config
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.properties import BooleanProperty

kivy.require('2.2.0')

Config.set('graphics', 'width', '450')
Config.set('graphics', 'height', '400')

Builder.load_string('''

<MainD>
    BoxLayout:
        orientation: 'vertical'
        size: root.size
        padding: 10

        RecycleView:
            id: rv
            viewclass: 'RVBox'
            SelectableRecycleBoxLayout:
                id: selectablervl
                default_size: None, None
                size_hint: 1, None
                height: self.minimum_height
                orientation: 'vertical'
                multiselect: True
                touch_multiselect: True    

        Button:
            text: 'Get Data'
            size_y: None
            size_hint_y: 0.2
            on_press: root.on_button_press()

<SelectableRecycleBoxLayout@FocusBehavior+LayoutSelectionBehavior+RecycleBoxLayout>

<RVBox>:
    text1: ''
    text2: ''

    id: rv
    size_hint: None, None
    width: self.ids.text1.width + self.ids.text2.width
    height: self.ids.text1.height
    canvas.before:
        Color:
            rgba: (0.0, 0.2, 0.9, 0.5) if self.selected else (0, 0, 0, 0)
        Rectangle:
            pos: self.pos
            size: self.size


    Label:
        id: text1
        size_hint: None, None
        size: 200, 60
        text: root.text1

    Label:
        id: text2
        size_hint: None, None
        size: 200, 60
        text: root.text2


''')


class RVBox(RecycleDataViewBehavior, BoxLayout):
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        self.index = index
        return super(RVBox, self).refresh_view_attrs(
            rv, index, data)

    def on_touch_down(self, touch):
        if super(RVBox, 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):
        self.selected = is_selected


class MainD(Widget):

    def __init__(self, **kwargs):
        super(MainD, self).__init__(**kwargs)
        self.ids.rv.data = [
            {'text1': 'text1 = 1', 'text2': 'text2 = 4'},
            {'text1': 'text1 = 2', 'text2': 'text2 = 3'},
            {'text1': 'text1 = 3', 'text2': 'text2 = 2'},
            {'text1': 'text1 = 4', 'text2': 'text2 = 1'},
            {'text1': 'text1 = 1', 'text2': 'text2 = 4'},
            {'text1': 'text1 = 2', 'text2': 'text2 = 3'},
            {'text1': 'text1 = 3', 'text2': 'text2 = 2'},
            {'text1': 'text1 = 4', 'text2': 'text2 = 1'},
            ]

    def on_button_press(self):
        select_index = self.ids.selectablervl.selected_nodes
        for index in select_index:
            print(f"{index}: {self.ids.rv.data[index]}")
        print("以上です。")


class MainDApp(App):
    def __init__(self, **kwargs):
        super(MainDApp, self).__init__(**kwargs)
        self.title = 'RecycleView Test5'

    def build(self):
        return MainD()


if __name__ == '__main__':
    app = MainDApp()
    app.run()
タイトルとURLをコピーしました