【问题标题】:how can i deselect a previously selected row in kivy recycleview如何在 kivy recycleview 中取消选择先前选择的行
【发布时间】:2018-09-30 08:50:04
【问题描述】:

我需要帮助在 RecycleView 中使用 SelectableLabel 视图取消选择选定的标签项。 任何想法如何解决它?

我知道它应该写在“def apply_selection”的某个地方,但我无法让它工作

示例:

我希望能够再次单击选定的行,并且选择将被删除。

我认为这个代码应该放在这里:

    def apply_selection(self, rv, index, is_selected):
    ''' Respond to the selection of items in the view. '''
        self.selected = is_selected

我尝试使用第三个输入来指定当前选择,但它并没有真正起作用。 1.这个方法是我需要修改的地方以实现我想要的吗? 2. 如果是这样,有什么正确的方法吗?

【问题讨论】:

  • 欢迎来到 Stack Overflow!请查看我们的SO Question Checklist 以帮助您提出一个好问题,从而得到一个好的答案。请粘贴您已经尝试过的代码的最小、完整且可验证的示例。
  • 编辑了我的帖子,感谢关注
  • @amihai 请阅读How to Ask 并提供minimal reproducible example

标签: python kivy kivy-language


【解决方案1】:

下面的代码就是按照要求做的,也就是

  1. 一次只启用一个选择,并且
  2. 启用取消选择所选项目

它与第一个答案的代码相同,除了突出显示的 3 个不同之处 ** 差异**。

从 kivy.app 导入应用程序
从 kivy.lang 导入生成器
从 kivy.uix.recycleview 导入 RecycleView
从 kivy.uix.recycleview.views 导入 RecycleDataViewBehavior
从 kivy.uix.label 导入标签
从 kivy.properties 导入 布尔属性
从 kivy.uix.recycleboxlayout 导入 回收箱布局
从 kivy.uix.behaviors 导入 FocusBehavior
从 kivy.uix.recycleview.layout 导入布局选择行为

Builder.load_string('''
<SelectableLabel>:
    # Draw a background to indicate selection
    canvas.before:
        Color:
            rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
        Rectangle:
            pos: self.pos
            size: self.size
<RV>:
    viewclass: 'SelectableLabel'
    SelectableRecycleBoxLayout:
        default_size: None, dp(56)
        default_size_hint: 1, None
        size_hint_y: None
        height: self.minimum_height
        orientation: 'vertical'
        multiselect: False # ** DIFFERENCE **
        touch_multiselect: False # ** DIFFERENCE **
''')


class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                                 RecycleBoxLayout):
    ''' Adds selection and focus behaviour to the view. '''

    # required to authorise unselecting a selected item
    touch_deselect_last = BooleanProperty(True) # ** DIFFERENCE **


class SelectableLabel(RecycleDataViewBehavior, Label):
    ''' Add selection support to the Label '''
    index = None
    selected = BooleanProperty(False)
    selectable = BooleanProperty(True)

    def refresh_view_attrs(self, rv, index, data):
        ''' Catch and handle the view changes '''
        self.index = index
        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 = not self.selected


class RV(RecycleView):
    def __init__(self, **kwargs):
        super(RV, self).__init__(**kwargs)
        self.data = [{'text': str(x)} for x in range(100)]


class RVMainApp(App):
    def build(self):
        return RV()


if __name__ == '__main__':
    RVMainApp().run()

【讨论】:

    【解决方案2】:

    常见问题解答

    您是否希望能够多选行,然后取消选择 个别行? – ikolim 2018 年 9 月 30 日 21:04

    不只是按一次选择,然后再按一次取消选择 ,而且在选择不同的行时也要保持选择的变化。 也许更容易说我正在寻找列表视图行为 recycleview – amihai 2018 年 9 月 30 日 21:07

    解决方案

    以下解决方案不适用于multi-select

    如果未选择行则设置为选中,或者在已选中时取消选择。

    片段

    def apply_selection(self, rv, index, is_selected):
        ''' Respond to the selection of items in the view. '''
        self.selected = not self.selected
    

    示例

    main.py

    ​​>
    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.properties import BooleanProperty
    from kivy.uix.recycleboxlayout import RecycleBoxLayout
    from kivy.uix.behaviors import FocusBehavior
    from kivy.uix.recycleview.layout import LayoutSelectionBehavior
    
    Builder.load_string('''
    <SelectableLabel>:
        # Draw a background to indicate selection
        canvas.before:
            Color:
                rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
            Rectangle:
                pos: self.pos
                size: self.size
    <RV>:
        viewclass: 'SelectableLabel'
        SelectableRecycleBoxLayout:
            default_size: None, dp(56)
            default_size_hint: 1, None
            size_hint_y: None
            height: self.minimum_height
            orientation: 'vertical'
    ''')
    
    
    class SelectableRecycleBoxLayout(FocusBehavior, LayoutSelectionBehavior,
                                     RecycleBoxLayout):
        ''' Adds selection and focus behaviour to the view. '''
    
    
    class SelectableLabel(RecycleDataViewBehavior, Label):
        ''' Add selection support to the Label '''
        index = None
        selected = BooleanProperty(False)
        selectable = BooleanProperty(True)
    
        def refresh_view_attrs(self, rv, index, data):
            ''' Catch and handle the view changes '''
            self.index = index
            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 = not self.selected
    
    
    class RV(RecycleView):
        def __init__(self, **kwargs):
            super(RV, self).__init__(**kwargs)
            self.data = [{'text': str(x)} for x in range(100)]
    
    
    class TestApp(App):
        def build(self):
            return RV()
    
    
    if __name__ == '__main__':
        TestApp().run()
    

    输出

    【讨论】:

    • 我希望得到你的答案@ikolim,你的答案总是如此详尽。这并不能完全解决我的问题,因为我希望能够压制选定的行并清除该选择(在我的情况下根本没有选择)。
    • 您希望能够多选行,然后取消选择单个行吗?
    • 不是单按选择,再按取消选择,而是在选择不同的行时保持选择的变化。也许更容易说我在这个 recycleview 中寻找 listview 行为
    • 就这么简单.. 再次感谢您在 SO 中的回答教会了我很多东西!
    • 对不起,多选仍然存在。选择新行不会取消选择之前选择的行!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-10
    • 2016-11-14
    • 1970-01-01
    • 2010-09-20
    • 1970-01-01
    • 2016-05-26
    相关资源
    最近更新 更多