【问题标题】:How can I stop Kivy from auto-selecting items modulo n in a RecycleView?如何阻止 Kivy 在 RecycleView 中自动选择模数项?
【发布时间】:2020-08-24 11:20:26
【问题描述】:

情况: 下面的代码使用 Kivy 的 RecycleView 类生成一个显示数据表的 GUI。该表的每一行都以一个红色的“忽略”按钮开始,用户应该能够通过单击该按钮的颜色在红色和绿色之间切换。

问题:当我点击一行的“忽略”按钮时,它不仅将点击的按钮变为绿色,而且还将列表下方的许多其他按钮变为绿色!不需要的选择会循环发生,也就是说,似乎每个 n 按钮都会变成绿色。

为什么会这样?我怎样才能让 Kivy 停止这样做,而是选择仅被点击的按钮?

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()

【问题讨论】:

    标签: python python-3.x user-interface kivy selection


    【解决方案1】:

    使用 Recycleview,您可以看到尽可能多的小部件……它们会被回收。因此,您不能依赖小部件来存储状态。 在 Row 中,我创建了一个 NumericProperty,idx,并在 rvdata 列表中创建了一个索引。这对应于“虚拟小部件”的索引。
    我创建了一个列表来存储 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()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多