我正在使用 python-2.7 和 kivy。当我运行 test.py
并单击 Test
菜单时,屏幕显示如附加图像。
1. 如何在屏幕加载时默认突出显示
第一行?当按下键盘的上
和下
键时,应该根据上
和下
键选择行。
2. 当我单击任何行时,它会在 modify
情况下打开。如何使用 ctrl+e
而不是在 modify
情况下打开选定的行点击?
测试.py
import kivy
kivy.require('1.9.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, ObjectProperty,NumericProperty
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
from kivy.core.window import Window
Window.size = (600, 325)
from kivy.clock import Clock
class EditStatePopup(Popup):
col_data = ListProperty(["?", "?"])
index = NumericProperty(0)
def __init__(self, obj, **kwargs):
super(EditStatePopup, self).__init__(**kwargs)
self.index = obj.index
self.col_data[0] = obj.rv_data[self.index]["Id"]
self.col_data[1] = obj.rv_data[self.index]["Name"]
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button):
''' Add selection support to the Button '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
rv_data = ObjectProperty(None)
start_point = NumericProperty(0)
def __init__(self, **kwargs):
super(SelectableButton, self).__init__(**kwargs)
Clock.schedule_interval(self.update, .0005)
def update(self, *args):
self.text = self.rv_data[self.index][self.key]
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, 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):
self.selected = is_selected
self.rv_data = rv.data
def on_press(self):
popup = EditStatePopup(self)
popup.open()
class MyRV(RecycleView):
def __init__(self, **kwargs):
super(MyRV, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
self._keyboard.bind(on_key_down=self._on_keyboard_down)
self.selectedItem = -1
def _keyboard_closed(self):
pass
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'down':
self.clearAll()
self.nextItem()
print('down')
elif keycode[1] == 'up':
self.clearAll()
self.prevItem()
print("up")
elif keycode[1] == 'e' and len(modifiers) > 0 and modifiers[0] == 'ctrl':
self.view_adapter.views[self.selectedItem].on_press()
def clearAll(self):
if (self.selectedItem > -1):
for i in range(len(self.view_adapter.views) - 1):
self.view_adapter.views[self.selectedItem].selected = 0
def nextItem(self):
if self.selectedItem < len(self.view_adapter.views) - 1:
self.selectedItem += 1
else:
self.selectedItem = 0
self.view_adapter.views[self.selectedItem].selected = 1
print(self.selectedItem)
def prevItem(self):
if self.selectedItem > 0:
self.selectedItem -= 1
else:
self.selectedItem = len(self.view_adapter.views) - 1
self.view_adapter.views[self.selectedItem].selected = 1
print(self.selectedItem)
class RV(RecycleView):
data_items = ListProperty([])
col1 = ListProperty()
col2 = ListProperty()
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_states()
def update(self):
self.col1 = [{'Id': str(x[0]), 'Name': x[1], 'key': 'Id', 'text': str(x[2])} for x in self.data_items]
self.col2 = [{'Id': str(x[0]), 'Name': x[1], 'key': 'Name', 'text': str(x[2])} for x in self.data_items]
def get_states(self):
rows = [(1, 'Test1'), (2, 'Test2'), (3, 'Test3')]
i = 0
for row in rows:
self.data_items.append([row[0], row[1], i])
i += 1
print(self.data_items)
self.update()
class MainMenu(BoxLayout):
states_cities_or_areas = ObjectProperty()
def display_states(self):
self.remove_widgets()
self.rv = RV()
self.states_cities_or_areas.add_widget(self.rv)
def remove_widgets(self):
self.states_cities_or_areas.clear_widgets()
class TestApp(App):
title = "test"
def build(self):
return MainMenu()
if __name__ == '__main__':
TestApp().run()
测试.kv
<SelectableButton>:
canvas.before:
Color:
rgba: (10, 10, 10, 10) if self.selected else (0, 0.517, 0.705, 1)
Rectangle:
pos: self.pos
size: self.size
<MyRV@RecycleView>:
viewclass: 'SelectableButton'
SelectableRecycleGridLayout:
cols: 1
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
<RV>:
BoxLayout:
orientation: "vertical"
viewclass: 'SelectableButton'
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
Label:
size_hint_x: .1
text: "Id"
Label:
size_hint_x: .5
text: "Name"
BoxLayout:
MyRV:
size_hint_x: .1
data: root.col1
MyRV:
size_hint_x: .5
data: root.col2
<EditStatePopup>:
size_hint: None, None
title_size: 20
title_font: "Verdana"
size: 400, 275
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
#backgroun_color: 0, 0.517, 0.705, 1
spacing: 10, 10
padding: 20, 20
Label:
text: "Id"
text_size: self.size
Label:
text: root.col_data[0]
text_size: self.size
Label:
text: "Name"
text_size: self.size
valign: 'middle'
TextInput:
focus : True
text: root.col_data[1]
text_size: self.size
GridLayout:
cols: 2
padding: 10, 0, 10, 10
spacing: 10, 10
row_default_height: '20dp'
size_hint: .5, .2
pos_hint: {'x': .25, 'y':.65}
Button:
text: 'Ok'
Button:
text: 'Cancel'
size_hint_x: .5
on_release: root.dismiss()
<MenuButton@Button>:
text_size: self.size
valign: "middle"
padding_x: 5
size : (80,30)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
<MainMenu>:
states_cities_or_areas: states_cities_or_areas
BoxLayout:
orientation: 'vertical'
#spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 1
MenuButton:
id: btn
text: 'Test'
size : (60,30)
on_release: root.display_states()
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: (1,1,1)
Label:
size_hint_x: 45
BoxLayout:
id: states_cities_or_areas
size_hint_y: 10
Label:
size_hint_y: 1
最佳答案
- 在 SelectableButton 上使用 2 种不同的颜色
- 检查按键并触发 on_press
文本.kv
<SelectableButton>:
canvas.before:
Color:
rgba: (0.5, 0.5, 0.5, 1) if self.selected else (0, 0.517, 0.705, 1)
Rectangle:
pos: self.pos
size: self.size
<MyRV@RecycleView>:
viewclass: 'SelectableButton'
SelectableRecycleGridLayout:
cols: 1
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
<RV>:
BoxLayout:
orientation: "vertical"
viewclass: 'SelectableButton'
GridLayout:
size_hint: 1, None
size_hint_y: None
height: 25
cols: 3
Label:
size_hint_x: .1
text: "Id"
Label:
size_hint_x: .5
text: "Name"
BoxLayout:
MyRV:
size_hint_x: .1
data: root.col1
MyRV:
size_hint_x: .5
data: root.col2
<EditStatePopup>:
size_hint: None, None
title_size: 20
title_font: "Verdana"
size: 400, 275
auto_dismiss: False
BoxLayout:
orientation: "vertical"
GridLayout:
cols: 2
#backgroun_color: 0, 0.517, 0.705, 1
spacing: 10, 10
padding: 20, 20
Label:
text: "Id"
text_size: self.size
Label:
text: root.col_data[0]
text_size: self.size
Label:
text: "Name"
text_size: self.size
valign: 'middle'
TextInput:
text: root.col_data[1]
text_size: self.size
<MenuButton@Button>:
text_size: self.size
valign: "middle"
padding_x: 5
size : (80,30)
size_hint : (None, None)
background_color: 90 , 90, 90, 90
background_normal: ''
color: 0, 0.517, 0.705, 1
border: (0, 10, 0, 0)
<MainMenu>:
states_cities_or_areas: states_cities_or_areas
BoxLayout:
orientation: 'vertical'
#spacing : 10
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
size_hint_y: 1
MenuButton:
id: btn
text: 'Test'
size : (60,30)
on_release: root.display_states()
BoxLayout:
canvas.before:
Rectangle:
pos: self.pos
size: self.size
Color:
rgb: (1,1,1)
Label:
size_hint_x: 45
BoxLayout:
id: states_cities_or_areas
size_hint_y: 10
Label:
size_hint_y: 1
测试应用程序.py
import kivy
kivy.require('1.9.0')
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import BooleanProperty, ListProperty, ObjectProperty,NumericProperty
from kivy.lang import Builder
from kivy.uix.recycleview import RecycleView
from kivy.uix.recycleview.views import RecycleDataViewBehavior
from kivy.uix.button import Button
from kivy.uix.recyclegridlayout import RecycleGridLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.uix.popup import Popup
from kivy.core.window import Window
Window.size = (600, 325)
from kivy.clock import Clock
class EditStatePopup(Popup):
col_data = ListProperty(["?", "?"])
index = NumericProperty(0)
def __init__(self, obj, **kwargs):
super(EditStatePopup, self).__init__(**kwargs)
self.index = obj.index
self.col_data[0] = obj.rv_data[self.index]["Id"]
self.col_data[1] = obj.rv_data[self.index]["Name"]
class SelectableRecycleGridLayout(FocusBehavior, LayoutSelectionBehavior,
RecycleGridLayout):
''' Adds selection and focus behaviour to the view. '''
class SelectableButton(RecycleDataViewBehavior, Button):
''' Add selection support to the Button '''
index = None
selected = BooleanProperty(False)
selectable = BooleanProperty(True)
rv_data = ObjectProperty(None)
start_point = NumericProperty(0)
def __init__(self, **kwargs):
super(SelectableButton, self).__init__(**kwargs)
Clock.schedule_interval(self.update, .0005)
def update(self, *args):
self.text = self.rv_data[self.index][self.key]
def refresh_view_attrs(self, rv, index, data):
''' Catch and handle the view changes '''
self.index = index
return super(SelectableButton, self).refresh_view_attrs(rv, index, data)
def on_touch_down(self, touch):
''' Add selection on touch down '''
if super(SelectableButton, 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):
self.selected = is_selected
self.rv_data = rv.data
def on_press(self):
popup = EditStatePopup(self)
popup.open()
class MyRV(RecycleView):
def __init__(self, **kwargs):
super(MyRV, self).__init__(**kwargs)
self._keyboard = Window.request_keyboard(self._keyboard_closed, self)
self._keyboard.bind(on_key_down=self._on_keyboard_down)
self.selectedItem = -1
def _keyboard_closed(self):
pass
def _on_keyboard_down(self, keyboard, keycode, text, modifiers):
if keycode[1] == 'down':
self.clearAll()
self.nextItem()
print('down')
elif keycode[1] == 'up':
self.clearAll()
self.prevItem()
print("up")
elif keycode[1] == 'e' and len(modifiers) > 0 and modifiers[0] == 'ctrl':
self.view_adapter.views[self.selectedItem].on_press()
def clearAll(self):
if (self.selectedItem > -1):
for i in range(len(self.view_adapter.views) - 1):
self.view_adapter.views[self.selectedItem].selected = 0
def nextItem(self):
if self.selectedItem < len(self.view_adapter.views) - 1:
self.selectedItem += 1
else:
self.selectedItem = 0
self.view_adapter.views[self.selectedItem].selected = 1
print(self.selectedItem)
def prevItem(self):
if self.selectedItem > 0:
self.selectedItem -= 1
else:
self.selectedItem = len(self.view_adapter.views) - 1
self.view_adapter.views[self.selectedItem].selected = 1
print(self.selectedItem)
class RV(RecycleView):
data_items = ListProperty([])
col1 = ListProperty()
col2 = ListProperty()
def __init__(self, **kwargs):
super(RV, self).__init__(**kwargs)
self.get_states()
def update(self):
self.col1 = [{'Id': str(x[0]), 'Name': x[1], 'key': 'Id', 'text': str(x[2])} for x in self.data_items]
self.col2 = [{'Id': str(x[0]), 'Name': x[1], 'key': 'Name', 'text': str(x[2])} for x in self.data_items]
def get_states(self):
rows = [(1, 'Test1'), (2, 'Test2'), (3, 'Test3')]
i = 0
for row in rows:
self.data_items.append([row[0], row[1], i])
i += 1
print(self.data_items)
self.update()
class MainMenu(BoxLayout):
states_cities_or_areas = ObjectProperty()
def display_states(self):
self.remove_widgets()
self.rv = RV()
self.states_cities_or_areas.add_widget(self.rv)
def remove_widgets(self):
self.states_cities_or_areas.clear_widgets()
class TestApp(App):
title = "test"
def build(self):
return MainMenu()
if __name__ == '__main__':
TestApp().run()
关于python-2.7 - Python/Kivy : Selection Row in RecycleView using `Up` and `Down` key,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49732096/