python-3.x - Kivy:如何通过向上或向下按钮保持选中的 RecycleView 列表项移动,以便进一步移动?
问题描述
下面的代码显示了可选项目的列表。选择一个项目后,可以使用适当的按钮在列表中向上或向下移动它。移动项目后,它不会保持选中状态,因此可以再次移动它。我不知道如何解决这个问题。
kivyrecycleview_movebuttons.kv 文件
<KivyRecycleView>:
orientation: "vertical"
recycleViewList: recycleView_list
moveUpButton: moveUp_Button
moveDownButton: moveDown_Button
boxLayoutContainingRV: boxlayout_recycleview
BoxLayout:
pos_hint: {'top': 1}
size_hint_y: 0.2
height: "28dp"
Button:
id: moveUp_Button
text: "^"
size_hint_x: 1
on_press: root.moveUpSelItem()
Button:
id: moveDown_Button
text: "v"
size_hint_x: 1
on_press: root.moveDownSelItem()
BoxLayout:
id: boxlayout_recycleview
size_hint_y: 0.8
height: "60dp"
RecycleView:
id: recycleView_list
scroll_y: 0 # forces scrolling to list bottom after adding an entry
effect_cls: "ScrollEffect" # prevents overscrolling
viewclass: 'SelectableLabel'
SelectableRecycleBoxLayout:
default_size: None, dp(15) # height of list line
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
spacing: 0.5
orientation: 'vertical'
multiselect: False
touch_multiselect: False
<SelectableLabel>:
# Draw a background to indicate selection
canvas.before:
Color:
rgba: (1, 0, 0, 1) if self.selected else (.0, 0.9, .1, .3)
Rectangle:
pos: self.pos
size: self.size
Color:
rgba: (0, 0.9, .1, .3)
Rectangle:
pos: self.pos
size: self.size
kivyrecycleview_movebuttons.py 文件
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
# RecycleView related imports
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
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)
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. '''
if not self.selected and not is_selected:
# case when adding a new list item
return
elif self.selected and not is_selected:
# toggling from selected to unselected
self.selected = False
rv.parent.parent.recycleViewCurrentSelIndex = -1
else:
# toggling from unselected to selected
self.selected = not self.selected
rv.parent.parent.recycleViewCurrentSelIndex = index
class KivyRecycleView(BoxLayout):
recycleViewCurrentSelIndex = -1
def __init__(self, **kwargs):
super(KivyRecycleView, self).__init__(**kwargs)
self.populateList()
def populateList(self):
for i in range(6):
listEntry = {'text': 'line {}'.format(i)}
self.recycleViewList.data.append(listEntry)
def moveUpSelItem(self):
oldIndex = self.recycleViewCurrentSelIndex
newIndex = oldIndex - 1
requestTotalNumber = len(self.recycleViewList.data)
if newIndex < 0:
# if first line request is moved up, it is moved at the end of the
# request history list
newIndex = requestTotalNumber - 1
self.moveItemInList(list=self.recycleViewList.data, oldIndex=oldIndex, newIndex=newIndex)
def moveDownSelItem(self):
oldIndex = self.recycleViewCurrentSelIndex
newIndex = oldIndex + 1
requestTotalNumber = len(self.recycleViewList.data)
if newIndex == requestTotalNumber:
# if last line request is moved down, it is moved at the beginning of the
# request history list
newIndex = 0
self.moveItemInList(list=self.recycleViewList.data, oldIndex=oldIndex, newIndex=newIndex)
def moveItemInList(self, list, oldIndex, newIndex):
list.insert(newIndex, list.pop(oldIndex))
class KivyRecycleView_moveButtonsApp(App):
def build(self): # implicitely looks for a kv file of name kivyrecycleview.kv which is
# class name without App, in lowercases
return KivyRecycleView()
if __name__ == '__main__':
dbApp = KivyRecycleView_moveButtonsApp()
dbApp.run()
解决方案
感谢您的上述评论。这是一个可行的解决方案(在 Windows 10 和 Android 上测试)。与初始代码相比的修改由 # <<------ 注释突出!我确信存在更简单的解决方案......
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
# RecycleView related imports
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.recycleview.views import RecycleDataViewBehavior
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)
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.rv = rv #<<------
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:
if self.rv.parent.parent.recycleViewCurrentSelIndex == self.index: #<<------
self.selected = False #<<------
self.rv.parent.parent.recycleViewCurrentSelIndex = -1 #<<------
else: #<<------
self.rv.parent.parent.recycleViewCurrentSelIndex = self.index #<<------
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. '''
if rv.parent.parent.recycleViewCurrentSelIndex == index: #<<------
is_selected = True #<<------
self.selected = False #<<------
else: #<<------
is_selected = False #<<------
self.selected = True #<<------
if not self.selected and not is_selected:
# case when adding a new list item
return
elif self.selected and not is_selected:
# toggling from selected to unselected
self.selected = False #<<------
else:
# toggling from unselected to selected
self.selected = not self.selected #<<------
class KivyRecycleView(BoxLayout):
recycleViewCurrentSelIndex = -1
def __init__(self, **kwargs):
super(KivyRecycleView, self).__init__(**kwargs)
# setting RecycleView list item height from config
self.populateList()
def populateList(self):
for i in range(6):
listEntry = {'text': 'line {}'.format(i)}
self.recycleViewList.data.append(listEntry)
def moveUpSelItem(self):
oldIndex = self.recycleViewCurrentSelIndex
if oldIndex == -1: #<<------
return
newIndex = oldIndex - 1
itemTotalNumber = len(self.recycleViewList.data)
if newIndex < 0:
# if first line request is moved up, it is moved at the end of the
# request history list
newIndex = itemTotalNumber - 1
self.moveItemInList(list=self.recycleViewList.data, oldIndex=oldIndex, newIndex=newIndex)
self.recycleViewCurrentSelIndex = newIndex #<<------
def moveDownSelItem(self):
oldIndex = self.recycleViewCurrentSelIndex
if oldIndex == -1: #<<------
return
newIndex = oldIndex + 1
itemTotalNumber = len(self.recycleViewList.data)
if newIndex == itemTotalNumber:
# if last line request is moved down, it is moved at the beginning of the
# request history list
newIndex = 0
self.moveItemInList(list=self.recycleViewList.data, oldIndex=oldIndex, newIndex=newIndex)
self.recycleViewCurrentSelIndex = newIndex #<<------
def moveItemInList(self, list, oldIndex, newIndex):
list.insert(newIndex, list.pop(oldIndex))
class KivyRecycleView_moveButtonsApp(App):
def build(self): # implicitely looks for a kv file of name kivyrecycleview.kv which is
# class name without App, in lowercases
return KivyRecycleView()
if __name__ == '__main__':
dbApp = KivyRecycleView_moveButtonsApp()
dbApp.run()
推荐阅读
- git - git-lfs:如何强制安装 git lfs?
- visual-studio - UWP 商店应用程序过期证书未由“将应用程序与商店关联”更新
- shell - 如果其他条件匹配语句在 jenkinsfile 的外壳中不起作用
- c - “__schedule”函数中的“current”和“prev”有什么区别,为什么不直接使用current呢?
- node.js - 如何在 .ejs 模板中显示错误
- php - 为什么 Jetstream 无法在我的 PC 上的 laravel 8 上安装
- javascript - 尝试使用 rpc.query 将数据从 javascript 发送到 python POS odoo
- firebase - 如何使用 ListView.builder 获取某个集合的特定 Firestore 文档
- python-3.x - 简单代码中的 type() 函数 SyntaxError
- linux - 将文件(特定扩展名)从文件夹结构复制到另一个文件夹