Reputation: 2437
I have a textinput that I want to focus on when the user clicks/touches on it. (Fairly standard!) It inherits from DragableObject (a user example in the kivy wiki) and GridLayout.
class DragableObject( Widget ):
def on_touch_down( self, touch ):
if self.collide_point( *touch.pos ):
touch.grab( self )
return True
def on_touch_up( self, touch ):
if touch.grab_current is self:
touch.ungrab( self )
return True
def on_touch_move( self, touch ):
if touch.grab_current is self:
self.pos = touch.x-self.width/2, touch.y-self.height/2
class MyWidget(DragableObject, GridLayout):
def __init__(self, **kwargs):
kwargs['orientation'] = 'lr-tb'
kwargs['spacing'] = 10
kwargs['size_hint'] = (None, None)
kwargs['size'] = (200, 80)
self.cols = 2
super(MyWidget, self).__init__(**kwargs)
with self.canvas:
self.rect = Rectangle(pos=self.pos, size=self.size)
with self.canvas.before:
Color(0, .5, 1, mode='rgb')
self.bind(pos=self.update_rect)
self.bind(size=self.update_rect)
self.add_widget(Label(text='t1'))
self.text1 = TextInput(multiline=False)
self.add_widget(self.text1)
self.add_widget(Label(text='t2'))
self.text2 = TextInput(multiline=False)
self.add_widget(self.text2)
# these bind's don't seem to work
self.text1.bind(on_touch_down=self.set_focus)
self.text1.bind(on_touch_up=self.set_focus)
self.text1.bind(on_touch_move=self.set_focus)
def set_focus(self):
print("pressed")
self.text1.focus = True
def update_rect(self, *args):
self.rect.pos = self.pos
self.rect.size = self.size
I have two problems.
a. The text input is unfocusable.
b. I can't get an event callback (such as on_touch_down) to work on the textinput widget.
Any ideas?
Upvotes: 3
Views: 4491
Reputation: 19037
Short Answer
You can simple use an Scatter
. It includes dragging, rotation and scaling functionality and you can deactivate any or all of them:
my_scatter = Scatter(do_rotation=False, do_scale=False)
None of the problems you described should happen inside a Scatter
Long Answer
Your problem is that you are overriding the on_touch_down
, on_touch_move
and on_touch_up
of the parent.
Normally these methods will call the corresponding ones of the children. For example, when the on_touch_down
method of a Widget
instance is called, then the Widget
instance is going to traverse its children, calling the on_touch_down
method of each of then (If you are familiarized with recursion and tree structures, we are talking about a recursive traverse method - I think pre-order - Tree traversal).
This functionality is overridden in the DraggableObject class. You got to be sure to call the method of be base class with:
super(DraggableWidget, self).on_touch_down(touch)
Depending on what is the behaviour you are looking for the methods could look like:
(1) If you always want to call the children:
def on_touch_down( self, touch ):
if self.collide_point( *touch.pos ):
touch.grab( self )
return super(DraggableWidget, self).on_touch_down(touch)
(2) If you just want to call the children when there is no collide:
def on_touch_down( self, touch ):
if self.collide_point( *touch.pos ):
touch.grab( self )
return True # Don't call the on_touch_down of the Base Class
return super(DraggableWidget, self).on_touch_down(touch)
And there is more options!. The return value indicates if the event was or not handled by any children. You can, for example, do something like this:
def on_touch_down( self, touch ):
handled = super(DraggableWidget, self).on_touch_down(touch)
if not handled and self.collide_point( *touch.pos ):
touch.grab( self )
return True
return handled
In this case, you will avoid the Widget to be dragged when one of the children handle the event. It all depends on what you do.
Upvotes: 10