maximus
maximus

Reputation: 2437

detecting click/touch in kivy textinput

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

Answers (1)

toto_tico
toto_tico

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

Related Questions