更改回收视图列宽
Changing Recycle View Column Widths
RecycleView
给我带来了一些麻烦,尤其是将列更改为特定大小时。我用 RecycleView
上方的 GridLayout
对预期的列宽进行了编码。当一个单元格通过使用模数 selected 时,我还采用了一种奇怪的方式 select 整行。我不确定这是否是最好的方法,但我希望得到其他人对此方法的意见。
我最终希望能够删除整行,然后是 JSON 文件中的 selected 数据。但现在,我只希望宽度适当。
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.storage.jsonstore import JsonStore
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
kv_string = """
ScreenManager:
id: manager
Screen:
BoxLayout:
orientation: 'vertical'
canvas:
Color:
rgba: .2,.2,.5,1
Rectangle:
pos: self.pos
size: self.size
GridLayout:
size_hint_y: .3
cols:4
MyButton:
text: 'Num'
size_hint_x: 0.5
MyButton:
text: 'Ratings'
MyButton:
text: 'Name'
size_hint_x: 2
MyButton:
text: 'Score'
on_press:
#arrange the boxing in ascending or descending order
RecycleView:
data: [{'text': str(x)} for x in app.data]
viewclass: 'SelectableLabel'
SelectableRecycleGridLayout:
cols: 4
#default_size: None, dp(26)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
ToggleButton:
id: toggle_button
size_hint_y: .3
text: 'Delete Selected'
state: 'normal'
on_press:
app.data = [0]
<SelectableLabel>:
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
<MyButton@Button>:
background_color: 0,0,0,1
"""
class SelectableLabel(RecycleDataViewBehavior, Label):
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
if super(SelectableLabel, self).on_touch_down(touch):
return True
# *** This selects the whole row *** # Not sure if this is the best way.
if self.collide_point(*touch.pos) and self.selectable:
self.parent.select_with_touch(self.index, touch)
if self.index % 4 == 0:
self.parent.select_with_touch(self.index + 1)
self.parent.select_with_touch(self.index + 2)
self.parent.select_with_touch(self.index + 3)
return
elif self.index % 4 == 1:
self.parent.select_with_touch(self.index + 1)
self.parent.select_with_touch(self.index + 2)
self.parent.select_with_touch(self.index -1)
return
elif self.index % 4 == 2:
self.parent.select_with_touch(self.index + 1)
self.parent.select_with_touch(self.index - 2)
self.parent.select_with_touch(self.index -1)
return
elif self.index % 4 == 3:
self.parent.select_with_touch(self.index - 1)
self.parent.select_with_touch(self.index - 2)
self.parent.select_with_touch(self.index - 3)
return
def apply_selection(self, rv, index, is_selected):
self.selected = is_selected
if App.get_running_app().root.ids.toggle_button.state == 'down':
print('Deleted', index) #Still need to add delete function
rv.layout_manager.clear_selection() #Not working
self.remove_widget(index) #Also not working
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior, RecycleGridLayout):
pass
class MyApp(App):
data = [] #ListProperty?
store = JsonStore('file.json')
store.put('Example: 1', value_1 = 'Rating: C', value_2 = 'Score: 10', value_3 = 'Name: Zack')
store.put('Example: 2', value_1 = 'Rating: A', value_2 = 'Score: 32', value_3 = 'Name: Pete')
store.put('Example: 3', value_1 = 'Rating: B', value_2 = 'Score: 24', value_3 = 'Name: Toby')
store.put('Example: 4', value_1 = 'Rating: D', value_2 = 'Score: 03', value_3 = 'Name: Lars')
x = 0
for rows in store.keys():
x += 1
data.append(x)
for row in store.get(rows):
data.append(store.get(rows)[row])
print(data) #shows successfully appended
def build(self):
root_widget = Builder.load_string(kv_string)
return root_widget
if __name__ == "__main__":
MyApp().run()
有点丑陋,但您可以将 refresh_view_layout
方法添加到 SelectableLabel
class:
def refresh_view_layout(self, rv, index, layout, viewport):
mod = index % 4
if mod == 0:
layout['size_hint'] = (0.15, None)
elif mod == 1:
layout['size_hint'] = (0.225, None)
elif mod == 2:
layout['size_hint'] = (0.225, None)
elif mod == 3:
layout['size_hint'] = (0.4, None)
super(SelectableLabel, self).refresh_view_layout( rv, index, layout, viewport)
因此,您可以将每个 SelectableLabel
的 size_hint
设置为您想要的任何值。如果您使 size_hint_x
与用于 Button
列 headers 的 size_hint_x
一致,我想您会得到想要的。
RecycleView
给我带来了一些麻烦,尤其是将列更改为特定大小时。我用 RecycleView
上方的 GridLayout
对预期的列宽进行了编码。当一个单元格通过使用模数 selected 时,我还采用了一种奇怪的方式 select 整行。我不确定这是否是最好的方法,但我希望得到其他人对此方法的意见。
我最终希望能够删除整行,然后是 JSON 文件中的 selected 数据。但现在,我只希望宽度适当。
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
from kivy.properties import BooleanProperty
from kivy.uix.behaviors import FocusBehavior
from kivy.storage.jsonstore import JsonStore
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
kv_string = """
ScreenManager:
id: manager
Screen:
BoxLayout:
orientation: 'vertical'
canvas:
Color:
rgba: .2,.2,.5,1
Rectangle:
pos: self.pos
size: self.size
GridLayout:
size_hint_y: .3
cols:4
MyButton:
text: 'Num'
size_hint_x: 0.5
MyButton:
text: 'Ratings'
MyButton:
text: 'Name'
size_hint_x: 2
MyButton:
text: 'Score'
on_press:
#arrange the boxing in ascending or descending order
RecycleView:
data: [{'text': str(x)} for x in app.data]
viewclass: 'SelectableLabel'
SelectableRecycleGridLayout:
cols: 4
#default_size: None, dp(26)
default_size_hint: 1, None
size_hint_y: None
height: self.minimum_height
orientation: 'vertical'
multiselect: True
touch_multiselect: True
ToggleButton:
id: toggle_button
size_hint_y: .3
text: 'Delete Selected'
state: 'normal'
on_press:
app.data = [0]
<SelectableLabel>:
canvas.before:
Color:
rgba: (.0, 0.9, .1, .3) if self.selected else (0, 0, 0, 1)
Rectangle:
pos: self.pos
size: self.size
<MyButton@Button>:
background_color: 0,0,0,1
"""
class SelectableLabel(RecycleDataViewBehavior, Label):
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
def refresh_view_attrs(self, rv, index, data):
self.index = index
return super(SelectableLabel, self).refresh_view_attrs(
rv, index, data)
def on_touch_down(self, touch):
if super(SelectableLabel, self).on_touch_down(touch):
return True
# *** This selects the whole row *** # Not sure if this is the best way.
if self.collide_point(*touch.pos) and self.selectable:
self.parent.select_with_touch(self.index, touch)
if self.index % 4 == 0:
self.parent.select_with_touch(self.index + 1)
self.parent.select_with_touch(self.index + 2)
self.parent.select_with_touch(self.index + 3)
return
elif self.index % 4 == 1:
self.parent.select_with_touch(self.index + 1)
self.parent.select_with_touch(self.index + 2)
self.parent.select_with_touch(self.index -1)
return
elif self.index % 4 == 2:
self.parent.select_with_touch(self.index + 1)
self.parent.select_with_touch(self.index - 2)
self.parent.select_with_touch(self.index -1)
return
elif self.index % 4 == 3:
self.parent.select_with_touch(self.index - 1)
self.parent.select_with_touch(self.index - 2)
self.parent.select_with_touch(self.index - 3)
return
def apply_selection(self, rv, index, is_selected):
self.selected = is_selected
if App.get_running_app().root.ids.toggle_button.state == 'down':
print('Deleted', index) #Still need to add delete function
rv.layout_manager.clear_selection() #Not working
self.remove_widget(index) #Also not working
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior, RecycleGridLayout):
pass
class MyApp(App):
data = [] #ListProperty?
store = JsonStore('file.json')
store.put('Example: 1', value_1 = 'Rating: C', value_2 = 'Score: 10', value_3 = 'Name: Zack')
store.put('Example: 2', value_1 = 'Rating: A', value_2 = 'Score: 32', value_3 = 'Name: Pete')
store.put('Example: 3', value_1 = 'Rating: B', value_2 = 'Score: 24', value_3 = 'Name: Toby')
store.put('Example: 4', value_1 = 'Rating: D', value_2 = 'Score: 03', value_3 = 'Name: Lars')
x = 0
for rows in store.keys():
x += 1
data.append(x)
for row in store.get(rows):
data.append(store.get(rows)[row])
print(data) #shows successfully appended
def build(self):
root_widget = Builder.load_string(kv_string)
return root_widget
if __name__ == "__main__":
MyApp().run()
有点丑陋,但您可以将 refresh_view_layout
方法添加到 SelectableLabel
class:
def refresh_view_layout(self, rv, index, layout, viewport):
mod = index % 4
if mod == 0:
layout['size_hint'] = (0.15, None)
elif mod == 1:
layout['size_hint'] = (0.225, None)
elif mod == 2:
layout['size_hint'] = (0.225, None)
elif mod == 3:
layout['size_hint'] = (0.4, None)
super(SelectableLabel, self).refresh_view_layout( rv, index, layout, viewport)
因此,您可以将每个 SelectableLabel
的 size_hint
设置为您想要的任何值。如果您使 size_hint_x
与用于 Button
列 headers 的 size_hint_x
一致,我想您会得到想要的。