Reputation: 163
Is is possible to change background color of without touch events? Please refer to below code. self.collidepoint()
method always returns False
. I know that even if it will return True
it won't work because I should clear
RV.data
and build it again with new bcolor
which seems to be pretty slow way.
CODE
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
from kivy.core.window import Window
Builder.load_string('''
<SelectableLabel>:
# Draw a background to indicate selection
bcolor: root.bcolor
canvas.before:
Color:
rgba: (0, 0, 0, 1) if self.selected else self.bcolor
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: True
touch_multiselect: True
''')
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)
bcolor = (0,0,0,1)
def __init__(self, **kwargs):
super(SelectableLabel, self).__init__(**kwargs)
Window.bind(mouse_pos=self.light_up)
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 light_up(self, window, mouse_pos):
print('MOTION ', mouse_pos, self.collide_point(mouse_pos[0], mouse_pos[1]))
if self.collide_point(mouse_pos[0], mouse_pos[1]):
self.bcolor = (1,1,1,1)
else:
self.bcolor = (0, 0, 0, 1)
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()
Window.bind(on_motion=SelectableLabel.on_motion())
if __name__ == '__main__':
TestApp().run()
Upvotes: 0
Views: 566
Reputation: 39082
There are two problems with your code. I have posted a version of your code with what I think are corrections for those problems.
The first is that bcolor
in SelectableLabel
needs to be a ListProperty
(the kv
bindings do not work otherwise).
The second is that in your light_up()
method, you must convert the window coordinates into coordinates appropriate for passing to collide_point()
. To do this, I save a reference to the RV
instance in each SelectableLabel
(as self.root
). And use the to_local()
to do the coordinate transformation.
Also, the Window.bind()
in the build()
method is unnecessary.
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, ListProperty
from kivy.uix.recycleboxlayout import RecycleBoxLayout
from kivy.uix.behaviors import FocusBehavior
from kivy.uix.recycleview.layout import LayoutSelectionBehavior
from kivy.core.window import Window
Builder.load_string('''
<SelectableLabel>:
# Draw a background to indicate selection
bcolor: root.bcolor
canvas.before:
Color:
rgba: (0, 0, 0, 1) if self.selected else self.bcolor
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: True
touch_multiselect: True
''')
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)
bcolor = ListProperty([0,0,0,1])
def __init__(self, **kwargs):
super(SelectableLabel, self).__init__(**kwargs)
self.root = App.get_running_app().root
Window.bind(mouse_pos=self.light_up)
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 light_up(self, window, mouse_pos):
pos_in_parent = self.root.to_local(*mouse_pos)
print('MOTION ', pos_in_parent, self.collide_point(pos_in_parent[0], pos_in_parent[1]))
if self.collide_point(pos_in_parent[0], pos_in_parent[1]):
self.bcolor = (1,1,1,1)
else:
self.bcolor = (0, 0, 0, 1)
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()
Upvotes: 1