質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Kivy

Kivyは、Pythonを用いたNUI開発のためのオープンソースフレームワーク。マルチタッチなど多くの入力に対応したNUIアプリなどを開発することができます。多くの環境で動作するクロスプラットフォームです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

Q&A

解決済

1回答

1789閲覧

kivyで、recycleviewの行を削除したい

kintarock777

総合スコア34

Kivy

Kivyは、Pythonを用いたNUI開発のためのオープンソースフレームワーク。マルチタッチなど多くの入力に対応したNUIアプリなどを開発することができます。多くの環境で動作するクロスプラットフォームです。

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

0グッド

0クリップ

投稿2020/02/01 15:07

編集2020/02/09 15:36

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()を付けること
ぐらいしか思いつきませんでした。
今知りたいことは、

  1. detach_recycleview であっているかどうか?
  2. あっている場合、その削除Buttonと削除したい行をどのように関連づけるか?
  3. あと、kivyファイルの方に書き込んだ方がよいか、classの中にdefとして、

 書き込んだ方がよいかです。

知識がなさ過ぎて、質問の仕方もよくわからなくてすみません。

なんとかしてこの問題を解決したいので、
質問の仕方も含め、間違っていたらいろいろ教えてください。
よろしくお願いいたします。

kvファイルの中の削除buttonのon_pressにdetach_recycleview()を書き込んで、
実行したところ
NameError: name 'detach_recycleview' is not defined
がでました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

私は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と書いてあげてください。

投稿2020/02/11 03:08

編集2020/02/11 03:09
gottadiveintopy

総合スコア736

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

kintarock777

2020/02/11 12:43 編集

回答ありがとうございます。 実はこのコードは他のサイトで他の人が書いたもので、私自身はまだコードの意味をほとんど理解していません。 items_1、items_2の値を変えるなど分かる範囲でちょっといじってみた程度のことで、今回の質問もrecycleviewの行を削除する方法をちょちょっと教えてもらいたいという程度のことでした。 なので、gottadiveintopyさんの回答は難しすぎて、さっぱり理解できていないというのが正直なところです。 ただ、こうなったからには、ここでちゃんと理解しなければと思っています。すこし時間がかかりそうですが、このコードについて勉強しますので、 よかったら力を貸してください。 このトピックスは、「recycleviewの行を削除したい」ですので、 そこまでたどり着くのにものすごく時間がかかりそうです。 すみません。
kintarock777

2020/02/11 12:36

しかし、このトピックスで他のコードの質問をするのは、 マナー上よくないですよね?
gottadiveintopy

2020/02/11 14:19

質問と関係無いのなら良くないですね、おそらく。 RecycleViewなんですが上に書いたように'data'を介して表示するデータを制御するのが原則です。データを追加するにしよ削除するにしよ更新するにしよ この'data'に対して行います。そうすればRecycleViewに表示されているデータもそれに連動して更新されるので。それで'data'が何者なのかというとlistのような物です。pythonのlistの扱い方は知っていると思うので同じようにして'data'の要素を削除してあげてください。 ここで問題になるのが削除buttonがどうやって'data'へアクセスするかで、それが上に書いた"泥臭いやり方"になります。 ちなみにKv言語内でrootが何を指すかは知っておられますか?
kintarock777

2020/02/11 14:24

class SelectableLabel に関数を定義して、削除ボタンのon_pressに関連づけるのでしょうか?
gottadiveintopy

2020/02/11 14:31

そうしても構わないですが問題の本質とは関係ないですね。本質はSelectableLabelがどうやって自身が属するRecycleViewへアクセスするかです。
kintarock777

2020/02/11 14:36

root に関しては完全に理解していません。 selfはそれ自身の、rootはその上の階層のwidgetを参照するときにつけるみたいな感じで読んでいました。
kintarock777

2020/02/11 14:44

自身が属するrecycleviewとは、それぞれの行の中に入っている削除ボタンの属するrecycleviewという意味でしょうか?
kintarock777

2020/02/11 14:56

ごめんなさい、当初の質問の選択した行を削除したいというところを、 すっかり忘れてました。 削除するというところだけに目が行っていました。 いままでのいただいたアドバイスでいろいろ試してみます。
gottadiveintopy

2020/02/11 16:43 編集

上の階層というか各ruleにおけるの最上位のwidgetを指します。上のcodeでは<SelectableLabel>と<RV>という二つのruleがあるのでrule内でそれぞれSelectableLabelとRVを指す事になりますね。なのでon_pressの部分でrootと書けばSelectableLabelへの参照が得られます。そこからさらに"泥臭いやり方"を使うとRVへの参照を得られます。 on_press: root.parent.parent # <- RVへの参照 ここまで来たら後はRVのdataを操作してあげるだけです。今回の場合、SelectableLabelが自身のindexを知っている事もあってdata.pop(index)を使って削除してあげると良いと思いますよ。
kintarock777

2020/02/13 12: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メッセージからすると、インスタンス化されていないからという投稿を見かけましたが、どのように対処したらよいかわかりません。 教えてください。
gottadiveintopy

2020/02/13 13:14 編集

わざわざdata_pop()というmethodを作る必要は無いですね。そのまま 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を得るか を考えてみてください。前者はすでに分かっていると思いますよ。
kintarock777

2020/02/13 13:29

ヒント、ありがとうございました。 on_press: root.parent.parent.data.pop(root.index) ですね。 30秒でできました。 自分の応用力のなさに驚きます(笑) ちなみに、methodを作る場合でも同じ結果が得られる方法はありますか?
gottadiveintopy

2020/02/13 13:58 編集

良かったです :) 方法はありますよ。多分やり方は分かると思いますが。 data_pop()にindexを渡してやればいけると思いますよ。
kintarock777

2020/02/13 14:06

ありがとうございます。 methodの件はもう少しがんばってみます。 最後のselectableの部分を考えてみます。
kintarock777

2020/02/13 14:29

methodの件は解決しました。 on_press: root.data_pop() SelectableLabelクラスに、 def data_pop(self): self.parent.parent.data.pop(self.index) で出来ました。
kintarock777

2020/02/14 12:53

選択していない行は削除できないようにするの部分を考えてみました。 SelectableLabelクラスに、 ’’’ def data_pop(self): if self.selected == True: self.parent.parent.data.pop(self.index) ’’’ としたところ、選択した行を削除することには成功しました。 しかし、その行は選択されたままの状態で残ってしまって、該当するdataが、一つ削除され、それより下のdataがそのまま上に繰り上げられる状態になってしまいました。 2行以上選択した場合は、dataの繰り上げ機能により、当初選択していたdataとは一段ずれたdataを選択する状態になってしまいます。 この選択された行の解除と制御をしたいのですが、アドバイスよろしくお願いいたします。
gottadiveintopy

2020/02/17 09:47

ちょっと分からないですね。ここら辺はSelectable系の使い方を知っている人にお願いしたいです。
gottadiveintopy

2020/02/17 10:04

公式のSelectable系を使ったsampleに動的にdataの要素を削除するcodeを加えたところ 同じ症状になったので、KIVY側の不具合かもですね。
kintarock777

2020/02/17 11:52

回答ありがとうございます。 いろいろ調べていただきありがとうございました。 とにかく、行の削除まではできるようになりましたし、他にもいろいろ勉強になりました。 この問題も引き続き調べようとおもいますが、今回はこれで締めようとおもいます。 これからアドバイスよろしくお願いいたします。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問