如何使用 Kivy select RecycleView 中的整行
How to select entire row in RecycleView using Kivy
我是 python 的新手,但完全是 Kivy 的初学者。我发现围绕 Kivy 的文档很难解释,至少对我来说是这样。到目前为止,我已经能够创建一个 RecycleView,我可以在其中添加、删除和更改数据。理想情况下,我希望能够拥有任意数量的列,但每一行上的所有数据都属于一起。因此,如果我 select 一个,我想突出显示该行中的所有项目。我试过使用 togglebutton 但没有成功。我只是不知道如何通过 ID 或其他方法访问 RecycleView 中的每个单独的切换按钮。如果我可以单独访问每个切换按钮,我可以简单地将其状态更改为等于“向下”。到目前为止,我只能找到用户 select 编辑了哪一行(但不是那么优雅)。我通过计算每行的按钮数量并将其与 selected 按钮的索引进行比较来管理这一点。
这是我正在试验的一个例子,通常我更喜欢使用 .kv 文件:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.recycleview.views import RecycleDataViewBehavior
class MyButton(RecycleDataViewBehavior, ToggleButton):
index = None
def refresh_view_attrs(self, rv, index, data):
""" Catch and handle the view changes """
self.index = index
return super(MyButton, self).refresh_view_attrs(
rv, index, data)
class TestRecycleView(RecycleView):
items_per_row = 3
selected_data = None
selected_row = None
def find_row(self, instance):
self.selected_row = instance.index // self.items_per_row + 1
print('Row: ', self.selected_row)
self.selected_data = self.data[(self.selected_row - 1) * self.items_per_row: self.items_per_row
* self.selected_row]
print('Data: ', self.selected_data)
KV = '''
<MyButton>:
on_release:
app.root.find_row(self)
TestRecycleView:
data: [{'text': str(x)} for x in range(21)]
viewclass: 'MyButton'
id: rv_controller
target_id: None
RecycleGridLayout:
cols: 3
default_size_hint: 1, None
orientation: 'vertical'
key_selection: 'selectable'
default_size: None, dp(26)
size_hint_y: None
height: self.minimum_height
multiselect: True
touch_multiselect: True
'''
class Test(App):
def build(self):
root = Builder.load_string(KV)
# root.data = items
return root
Test().run()
因为我已经能够计算出用户 selected 了哪一行,所以我还可以计算 RecycleView 中正在被 selected 的数据。但是,我想要这种行的简洁视觉表示 selection.
非常感谢您的帮助。
您可以在 find_row()
方法中添加 hack 来设置一行中所有按钮的状态。此方法将它们设置为与所选 Button
实例的状态一致,因此您也可以取消选择。
def find_row(self, instance):
rgl = self.ids.gl
num_buttons = len(rgl.children)
num_rows = num_buttons // self.items_per_row
self.selected_row = instance.index // self.items_per_row + 1
print('Row: ', self.selected_row)
self.selected_data = self.data[(self.selected_row - 1) * self.items_per_row: self.items_per_row
* self.selected_row]
print('Data: ', self.selected_data)
index1 = (num_rows - self.selected_row + 1) * self.items_per_row - 1
index2 = index1 - self.items_per_row
state = instance.state
for index in range(index1, index2, -1):
rgl.children[index].state = state
这还需要将RecycleGridLayout
的id设置为:
id: gl
Buttons
是RecycleGridLayout
的children,所以可以用来得到Buttons
的总数。 children
列表中的索引与您的预期相反。即标记为 0
的 Button
是索引 20
,标记为 20
的 Button
是索引 0
。因此 index1
的计算使用该知识来确定所选行中 left-most Button
的索引。然后所选行中的 right-most Button
将是 index - 2
。 range(inde1, index2, -1)
遍历所选行中的 Buttons
。由于find_row()
被称为on_release
,instance
的state
已经被切换,所以它的state
可以用来设置state
的该行中的另一个 Buttons
。
我是 python 的新手,但完全是 Kivy 的初学者。我发现围绕 Kivy 的文档很难解释,至少对我来说是这样。到目前为止,我已经能够创建一个 RecycleView,我可以在其中添加、删除和更改数据。理想情况下,我希望能够拥有任意数量的列,但每一行上的所有数据都属于一起。因此,如果我 select 一个,我想突出显示该行中的所有项目。我试过使用 togglebutton 但没有成功。我只是不知道如何通过 ID 或其他方法访问 RecycleView 中的每个单独的切换按钮。如果我可以单独访问每个切换按钮,我可以简单地将其状态更改为等于“向下”。到目前为止,我只能找到用户 select 编辑了哪一行(但不是那么优雅)。我通过计算每行的按钮数量并将其与 selected 按钮的索引进行比较来管理这一点。
这是我正在试验的一个例子,通常我更喜欢使用 .kv 文件:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.recycleview.views import RecycleDataViewBehavior
class MyButton(RecycleDataViewBehavior, ToggleButton):
index = None
def refresh_view_attrs(self, rv, index, data):
""" Catch and handle the view changes """
self.index = index
return super(MyButton, self).refresh_view_attrs(
rv, index, data)
class TestRecycleView(RecycleView):
items_per_row = 3
selected_data = None
selected_row = None
def find_row(self, instance):
self.selected_row = instance.index // self.items_per_row + 1
print('Row: ', self.selected_row)
self.selected_data = self.data[(self.selected_row - 1) * self.items_per_row: self.items_per_row
* self.selected_row]
print('Data: ', self.selected_data)
KV = '''
<MyButton>:
on_release:
app.root.find_row(self)
TestRecycleView:
data: [{'text': str(x)} for x in range(21)]
viewclass: 'MyButton'
id: rv_controller
target_id: None
RecycleGridLayout:
cols: 3
default_size_hint: 1, None
orientation: 'vertical'
key_selection: 'selectable'
default_size: None, dp(26)
size_hint_y: None
height: self.minimum_height
multiselect: True
touch_multiselect: True
'''
class Test(App):
def build(self):
root = Builder.load_string(KV)
# root.data = items
return root
Test().run()
因为我已经能够计算出用户 selected 了哪一行,所以我还可以计算 RecycleView 中正在被 selected 的数据。但是,我想要这种行的简洁视觉表示 selection.
非常感谢您的帮助。
您可以在 find_row()
方法中添加 hack 来设置一行中所有按钮的状态。此方法将它们设置为与所选 Button
实例的状态一致,因此您也可以取消选择。
def find_row(self, instance):
rgl = self.ids.gl
num_buttons = len(rgl.children)
num_rows = num_buttons // self.items_per_row
self.selected_row = instance.index // self.items_per_row + 1
print('Row: ', self.selected_row)
self.selected_data = self.data[(self.selected_row - 1) * self.items_per_row: self.items_per_row
* self.selected_row]
print('Data: ', self.selected_data)
index1 = (num_rows - self.selected_row + 1) * self.items_per_row - 1
index2 = index1 - self.items_per_row
state = instance.state
for index in range(index1, index2, -1):
rgl.children[index].state = state
这还需要将RecycleGridLayout
的id设置为:
id: gl
Buttons
是RecycleGridLayout
的children,所以可以用来得到Buttons
的总数。 children
列表中的索引与您的预期相反。即标记为 0
的 Button
是索引 20
,标记为 20
的 Button
是索引 0
。因此 index1
的计算使用该知识来确定所选行中 left-most Button
的索引。然后所选行中的 right-most Button
将是 index - 2
。 range(inde1, index2, -1)
遍历所选行中的 Buttons
。由于find_row()
被称为on_release
,instance
的state
已经被切换,所以它的state
可以用来设置state
的该行中的另一个 Buttons
。