如何阻止 Kivy 在 RecycleView 中自动选择项目模数?
How can I stop Kivy from auto-selecting items modulo n in a RecycleView?
情况: 下面的代码使用 Kivy 的 RecycleView class 生成一个显示 table 数据的 GUI。此 table 的每一行都以一个红色的“忽略”按钮开头,用户应该可以通过单击该按钮的颜色在红色和绿色之间切换。
问题: 当我点击某行的“忽略”按钮时,它不仅将点击的按钮变为绿色,而且还将列表下方的许多其他按钮变为绿色,如下所示出色地!不需要的 selection 循环发生,也就是说,似乎每个 n-th 按钮都变成绿色。
为什么会这样?我怎样才能让 Kivy 停止这样做,取而代之的是 select 仅 被点击的按钮?
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
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
Builder.load_string('''
<Row@BoxLayout>:
orientation: 'horizontal'
data: [None, None, None, None]
IgnoreButton:
text: 'Ignored' if self.selected else 'Ignore'
background_normal: ''
# color green if ignored, otherwise red
background_color: [0.2, 0.5, 0.1, 1] if self.selected else [0.5, 0, 0.1, 1]
Label:
text: str(root.data[1])
Label:
text: str(root.data[2])
Label:
text: str(root.data[3])
<RV>:
viewclass: 'Row'
data: [{'data':[0, x, x+1, x+2]} for x in range(100)]
SelectableRecycleBoxLayout:
orientation: 'vertical'
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
multiselect: True
''')
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
' Adds selection and focus behaviour to the view. '
class IgnoreButton(Button, RecycleDataViewBehavior):
# Add selection support to the Button.
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def on_touch_down(self, touch):
# Add selection on touch down.
if super().on_touch_down(touch):
self.selected = not self.selected
class RV(RecycleView):
def __init__(self, **kwargs):
super().__init__(**kwargs)
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
使用 Recycleview,只有您能看到的小部件数量……它们会被回收。因此你不能依赖小部件来存储状态。
在 Row 中,我创建了一个 NumericProperty,idx,并在 rvdata 列表中创建了一个索引。这对应于“虚拟小部件”的索引。
我创建了一个列表来存储 ToggleButton 的状态。
您将 Button 视为 ToggleButton,因此我将其替换为 ToggleButton。您可以将颜色更改添加回来。
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import NumericProperty, ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView
Builder.load_string('''
<Row>:
orientation: 'horizontal'
data: [None, None, None, None]
ToggleButton:
text: 'Ignored' if app.root.selected[root.idx] == 'normal' else 'Ignore'
#background_normal: ''
# color green if ignored, otherwise red
#background_color: [0.2, 0.5, 0.1, 1] if app.root.selected[root.idx] == 'normal' else [0.5, 0, 0.1, 1]
state: app.root.selected[root.idx]
on_state: app.root.selected[root.idx] = self.state
Label:
text: str(root.data[1])
Label:
text: str(root.data[2])
Label:
text: str(root.data[3])
<RV>:
viewclass: 'Row'
data: [{'data':[0, x, x+1, x+2], 'idx': x} for x in range(100)]
RecycleBoxLayout:
orientation: 'vertical'
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
''')
class Row(BoxLayout):
idx = NumericProperty()
class RV(RecycleView):
selected = ListProperty(['normal'] * 100)
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
情况: 下面的代码使用 Kivy 的 RecycleView class 生成一个显示 table 数据的 GUI。此 table 的每一行都以一个红色的“忽略”按钮开头,用户应该可以通过单击该按钮的颜色在红色和绿色之间切换。
问题: 当我点击某行的“忽略”按钮时,它不仅将点击的按钮变为绿色,而且还将列表下方的许多其他按钮变为绿色,如下所示出色地!不需要的 selection 循环发生,也就是说,似乎每个 n-th 按钮都变成绿色。
为什么会这样?我怎样才能让 Kivy 停止这样做,取而代之的是 select 仅 被点击的按钮?
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.button import Button
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
Builder.load_string('''
<Row@BoxLayout>:
orientation: 'horizontal'
data: [None, None, None, None]
IgnoreButton:
text: 'Ignored' if self.selected else 'Ignore'
background_normal: ''
# color green if ignored, otherwise red
background_color: [0.2, 0.5, 0.1, 1] if self.selected else [0.5, 0, 0.1, 1]
Label:
text: str(root.data[1])
Label:
text: str(root.data[2])
Label:
text: str(root.data[3])
<RV>:
viewclass: 'Row'
data: [{'data':[0, x, x+1, x+2]} for x in range(100)]
SelectableRecycleBoxLayout:
orientation: 'vertical'
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
multiselect: True
''')
class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleBoxLayout):
' Adds selection and focus behaviour to the view. '
class IgnoreButton(Button, RecycleDataViewBehavior):
# Add selection support to the Button.
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def on_touch_down(self, touch):
# Add selection on touch down.
if super().on_touch_down(touch):
self.selected = not self.selected
class RV(RecycleView):
def __init__(self, **kwargs):
super().__init__(**kwargs)
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()
使用 Recycleview,只有您能看到的小部件数量……它们会被回收。因此你不能依赖小部件来存储状态。
在 Row 中,我创建了一个 NumericProperty,idx,并在 rvdata 列表中创建了一个索引。这对应于“虚拟小部件”的索引。
我创建了一个列表来存储 ToggleButton 的状态。
您将 Button 视为 ToggleButton,因此我将其替换为 ToggleButton。您可以将颜色更改添加回来。
from kivy.app import App
from kivy.lang import Builder
from kivy.properties import NumericProperty, ListProperty
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.recycleview import RecycleView
Builder.load_string('''
<Row>:
orientation: 'horizontal'
data: [None, None, None, None]
ToggleButton:
text: 'Ignored' if app.root.selected[root.idx] == 'normal' else 'Ignore'
#background_normal: ''
# color green if ignored, otherwise red
#background_color: [0.2, 0.5, 0.1, 1] if app.root.selected[root.idx] == 'normal' else [0.5, 0, 0.1, 1]
state: app.root.selected[root.idx]
on_state: app.root.selected[root.idx] = self.state
Label:
text: str(root.data[1])
Label:
text: str(root.data[2])
Label:
text: str(root.data[3])
<RV>:
viewclass: 'Row'
data: [{'data':[0, x, x+1, x+2], 'idx': x} for x in range(100)]
RecycleBoxLayout:
orientation: 'vertical'
default_size: None, dp(56)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
''')
class Row(BoxLayout):
idx = NumericProperty()
class RV(RecycleView):
selected = ListProperty(['normal'] * 100)
class TestApp(App):
def build(self):
return RV()
if __name__ == '__main__':
TestApp().run()