kivyで、recycleviewの行を削除したい
- 評価
- クリップ 0
- VIEW 611
kivyで recycleviewのリストに削除ボタンを設定しました。
選択した行を削除したいです。
選択していない行は、削除ボタンを押しても削除されないようにしたいです。
SelectablLabelクラスの中に削除用のモジュールを作りたいです。
あと、行が選択されているか否かの判別も行いたいです。
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.gridlayout import GridLayout
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
import japanize_kivy
Builder.load_string('''
<SelectableLabel>:
canvas.before:
Color:
rgba: (.8, .8, .8, 1) if self.selected else (1, .8, .8, 1)
Rectangle:
pos: self.pos
size: self.size
label1_text: 'label 1 text'
label2_text: 'label 2 text'
label3_text: 'label 3 text'
pos: self.pos
size: self.size
#Label:
# id: id_label1
# text: root.label1_text
# color: [0,0,0,1]
# font_size: 20
Label:
id: id_label2
text: root.label2_text
color: [0,0,0,1]
font_size: 20
size_hint_x: 4
Label:
id: id_label3
text: root.label3_text
color: [0,0,0,1]
font_size: 20
size_hint_x: 4
Button:
text: '削除'
font_size: 20
size_hint_x: 2
on_press: detach_recycleview() #どのように当該の行と関連づけるか?
<RV>:
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
default_size: None, dp(45)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
''')
items_1 = ['カツ丼','天丼','親子丼','玉子丼','オムライス','カツカレー']
items_2 = ['850','850','750','670','800','850']
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
pass
class SelectableLabel(RecycleDataViewBehavior, GridLayout):
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
cols = 3
def refresh_view_attrs(self, rv, index, data):
'''Catch and handle the view changes '''
self.index = index
self.label1_text = str(index)
self.label2_text = data['label2']['text']
self.label3_text = data['label3']['text']
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 {}'.format(rv.data[index]))
else:
print('selection removed for {}'.format(rv.data[index]))
class RV(RecycleView):
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
paired_iter = zip(items_1, items_2)
self.data = []
for i1, i2 in paired_iter:
d = {'label2': {'text': i1}, 'label3': {'text': i2}}
self.data.append(d)
class Menu01App(App):
def build(self):
return RV()
if __name__ == '__main__':
Menu01App().run()
よろしくお願いいたします。
その後調べましたが、削除Buttonのon_pressにdetach_recycleview()を付けること
ぐらいしか思いつきませんでした。
今知りたいことは、
- detach_recycleview であっているかどうか?
- あっている場合、その削除Buttonと削除したい行をどのように関連づけるか?
- あと、kivyファイルの方に書き込んだ方がよいか、classの中にdefとして、
書き込んだ方がよいかです。
知識がなさ過ぎて、質問の仕方もよくわからなくてすみません。
なんとかしてこの問題を解決したいので、
質問の仕方も含め、間違っていたらいろいろ教えてください。
よろしくお願いいたします。
kvファイルの中の削除buttonのon_pressにdetach_recycleview()を書き込んで、
実行したところ
NameError: name 'detach_recycleview' is not defined
がでました。
-
気になる質問をクリップする
クリップした質問は、後からいつでもマイページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
クリップを取り消します
-
良い質問の評価を上げる
以下のような質問は評価を上げましょう
- 質問内容が明確
- 自分も答えを知りたい
- 質問者以外のユーザにも役立つ
評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。
質問の評価を上げたことを取り消します
-
評価を下げられる数の上限に達しました
評価を下げることができません
- 1日5回まで評価を下げられます
- 1日に1ユーザに対して2回まで評価を下げられます
質問の評価を下げる
teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。
- プログラミングに関係のない質問
- やってほしいことだけを記載した丸投げの質問
- 問題・課題が含まれていない質問
- 意図的に内容が抹消された質問
- 過去に投稿した質問と同じ内容の質問
- 広告と受け取られるような投稿
評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。
質問の評価を下げたことを取り消します
この機能は開放されていません
評価を下げる条件を満たしてません
質問の評価を下げる機能の利用条件
この機能を利用するためには、以下の事項を行う必要があります。
- 質問回答など一定の行動
-
メールアドレスの認証
メールアドレスの認証
-
質問評価に関するヘルプページの閲覧
質問評価に関するヘルプページの閲覧
checkベストアンサー
+1
私はSelectableXXX
系の物は扱ったことは無いですが非SelectableXXX
系と同じやり方で一応できたので紹介しますね。RecycleView
において(少なくとも非SelectableXXX
系において)は基本的にRecycleView.data
を通して表示するデータを更新します。例えばこれに対してdata.pop(index)
やdata.remove(object)
とすることでデータを削除できます。それでSelectableLabel
側からどうやって自身が属するRecycleView
を得るかですが、私がよくやっているのがSelectableLabelのinstance.parent.parent
です。泥臭いやり方ですが他にやり方が見当たらないのでこうしています。
あとcols = 3
はまずい書き方ですね。kivyのpropertyはclass-levelで書き換えてはいけません。必ずinstance.cols = 3
とするかKv言語の方でcols: 3
と書いてあげてください。
投稿
-
回答の評価を上げる
以下のような回答は評価を上げましょう
- 正しい回答
- わかりやすい回答
- ためになる回答
評価が高い回答ほどページの上位に表示されます。
-
回答の評価を下げる
下記のような回答は推奨されていません。
- 間違っている回答
- 質問の回答になっていない投稿
- スパムや攻撃的な表現を用いた投稿
評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。
15分調べてもわからないことは、teratailで質問しよう!
- ただいまの回答率 88.37%
- 質問をまとめることで、思考を整理して素早く解決
- テンプレート機能で、簡単に質問をまとめられる
2020/02/11 21:35 編集
実はこのコードは他のサイトで他の人が書いたもので、私自身はまだコードの意味をほとんど理解していません。
items_1、items_2の値を変えるなど分かる範囲でちょっといじってみた程度のことで、今回の質問もrecycleviewの行を削除する方法をちょちょっと教えてもらいたいという程度のことでした。
なので、gottadiveintopyさんの回答は難しすぎて、さっぱり理解できていないというのが正直なところです。
ただ、こうなったからには、ここでちゃんと理解しなければと思っています。すこし時間がかかりそうですが、このコードについて勉強しますので、
よかったら力を貸してください。
このトピックスは、「recycleviewの行を削除したい」ですので、
そこまでたどり着くのにものすごく時間がかかりそうです。
すみません。
2020/02/11 21:36
マナー上よくないですよね?
2020/02/11 23:19
RecycleViewなんですが上に書いたように'data'を介して表示するデータを制御するのが原則です。データを追加するにしよ削除するにしよ更新するにしよ この'data'に対して行います。そうすればRecycleViewに表示されているデータもそれに連動して更新されるので。それで'data'が何者なのかというとlistのような物です。pythonのlistの扱い方は知っていると思うので同じようにして'data'の要素を削除してあげてください。
ここで問題になるのが削除buttonがどうやって'data'へアクセスするかで、それが上に書いた"泥臭いやり方"になります。
ちなみにKv言語内でrootが何を指すかは知っておられますか?
2020/02/11 23:24
2020/02/11 23:31
2020/02/11 23:36
selfはそれ自身の、rootはその上の階層のwidgetを参照するときにつけるみたいな感じで読んでいました。
2020/02/11 23:44
2020/02/11 23:56
すっかり忘れてました。
削除するというところだけに目が行っていました。
いままでのいただいたアドバイスでいろいろ試してみます。
2020/02/12 00:01 編集
on_press: root.parent.parent # <- RVへの参照
ここまで来たら後はRVのdataを操作してあげるだけです。今回の場合、SelectableLabelが自身のindexを知っている事もあってdata.pop(index)を使って削除してあげると良いと思いますよ。
2020/02/13 21:41
削除Buttonに on_press:root.parent.parent.data_pop() として、
RVクラスに、
def data_pop(self):
self.data.pop(0)
としたところ、どの削除Buttonを押しても、一番上の行を削除することに、成功しました。とりあえず、一歩進めました。
次の段階で、SelectableLabelが自身のindexを知っているということでしたが、それぞれの削除Buttonにindexを割りあてる方法がわかりません。
単純にRVの中に
def data_pop(self, index):
self.data.pop(self.index)
としてみましたが、
TypeError: data_pop() missing 1 required positional argument: 'index'
が出てダメでした。
on_press: root.data_pop()
と変えて、SelectableLabelクラスに、
def data_pop(self, index):
self.data.pop(self.index)
でやってみても同じ結果でした。
errorメッセージからすると、インスタンス化されていないからという投稿を見かけましたが、どのように対処したらよいかわかりません。
教えてください。
2020/02/13 22:13 編集
on_press:root.parent.parent.data.pop(...)
と書いてあげれば良いので。
> それぞれの削除Buttonにindexを割りあてる方法がわかりません。
削除Buttonにindexを割り当てる必要は無いですよ。ただon_press:の箇所でindexを得られればいいだけなので。on_press:の箇所で削除Buttonが属するSelectableLabelのindexをpop()の引数として渡してあげてください。
- on_press:の箇所で何を書けば削除Buttonが属するSelectableLabelが得られるか
- 得たSelectableLabelからどうやってindexを得るか
を考えてみてください。前者はすでに分かっていると思いますよ。
2020/02/13 22:29
on_press: root.parent.parent.data.pop(root.index)
ですね。
30秒でできました。
自分の応用力のなさに驚きます(笑)
ちなみに、methodを作る場合でも同じ結果が得られる方法はありますか?
2020/02/13 22:52 編集
方法はありますよ。多分やり方は分かると思いますが。
data_pop()にindexを渡してやればいけると思いますよ。
2020/02/13 23:06
methodの件はもう少しがんばってみます。
最後のselectableの部分を考えてみます。
2020/02/13 23:29
on_press: root.data_pop()
SelectableLabelクラスに、
def data_pop(self):
self.parent.parent.data.pop(self.index)
で出来ました。
2020/02/14 21:40
2020/02/14 21:53
SelectableLabelクラスに、
’’’
def data_pop(self):
if self.selected == True:
self.parent.parent.data.pop(self.index)
’’’
としたところ、選択した行を削除することには成功しました。
しかし、その行は選択されたままの状態で残ってしまって、該当するdataが、一つ削除され、それより下のdataがそのまま上に繰り上げられる状態になってしまいました。
2行以上選択した場合は、dataの繰り上げ機能により、当初選択していたdataとは一段ずれたdataを選択する状態になってしまいます。
この選択された行の解除と制御をしたいのですが、アドバイスよろしくお願いいたします。
2020/02/17 18:47
2020/02/17 19:04
2020/02/17 20:52
いろいろ調べていただきありがとうございました。
とにかく、行の削除まではできるようになりましたし、他にもいろいろ勉強になりました。
この問題も引き続き調べようとおもいますが、今回はこれで締めようとおもいます。
これからアドバイスよろしくお願いいたします。
ありがとうございました。
2020/05/13 18:16
https://youtu.be/1iB40vjQ-yw
https://qiita.com/gotta_dive_into_python/items/ed09e67e80316e472618