Search code examples
pythonpython-3.xkivykivy-language

Why is it that setting TextInput focus equal to True, makes TextInput not respond to keyboard input?


Background:

I have a button that adds TextInput widgets to a GridLayout with focus: True. If a TextInput is already present in the layout with focus = True, the previous TextInput is firstly unfocused then a new TextInput is added with focus = True.

Problem:

Once a TextInput is added I cannot type even though the cursor is focused on the added TextInput. Secondary problem is when an user clicks on another widget the TextInput stays focused. Meaning an unfocus event cannot be fired.

Tried:

I removed setting the focus explicitly, but then the desired result to start typing after adding a TextInput is lost. Secondary I tried setting unfocus_on_touch = True, but the TextInput stayed focused even after user left the TextInput.

Code:

import kivy
kivy.require("1.10.1")

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty
from kivy.uix.textinput import TextInput
from kivy.uix.bubble import Bubble
from kivy.lang import Builder

Builder.load_string('''
#: import Window kivy.core.window.Window
<Button>:
    background_normal: ''
<Label>:
    canvas.before:
        Color:
            rgba: (0,0.59,0.36,1)
        Rectangle:
            pos: self.pos
            size: self.size
<TextInput>:
    hint_text: 'Nuwe nota'
    font_size: self.height / 4.5 if self.focus else self.height / 3
    background_normal: ''
    background_active: ''
    focus: True
    foreground_color: (0,0.61,0.36,1) if self.focus else (0.71,0.75,0.71,1)
    canvas.after:
        Color:
            rgb: (0,0,0,1)
        Line:
            points: self.pos[0] , self.pos[1], self.pos[0] + self.size[0], self.pos[1]
    size_hint_y: None
    height: Window.height / 6 if self.focus else Window.height / 12
<ChoiceBubble>:
    orientation: 'horizontal'
    size_hint: (None, None)
    size: (160, 120)
    pos_hint: {'top': 0.2, 'right': 0.8}
    arrow_pos: 'top_left'
    BubbleButton:
        text: 'Save'
    BubbleButton:
        text: 'Encrypt..'
    BubbleButton:
        text: 'Delete'
        on_release: root.del_txt_input()
<Notation>:
    canvas:
        Color:
            rgba: (0,0.43,0.37,1)
        Rectangle:
            pos: self.pos
            size: self.size
    Label:
        pos_hint: {'top': 1, 'right': 0.8}
        size_hint: [0.8, None]
        height: Window.height / 15
    Button:
        text: 'Set'
        color: (0,0,0,1)
        pos_hint: {'top': 1, 'right': 0.9}
        size_hint: [0.1, None]
        height: Window.height / 15

    Button:
        text: '+ Plus'
        color: (0,0,0,1)
        pos_hint: {'top': 1, 'right': 1}
        size_hint: [0.1, None]
        height: Window.height / 15
        on_release: root.add_input()
    ScrollView:
        size_hint_y: None
        size: Window.width, Window.height
        pos_hint: {'top': 0.92, 'right': 1}
        GridLayout:
            id: text_holder
            cols: 1
            pos_hint: {'top': 0.92, 'right': 1}
            padding: 4
            size_hint_x: 1
            size_hint_y: None
            height: self.minimum_height

''')
class ChoiceBubble(Bubble):
    pass
class Notation(FloatLayout):
    which_txt = ObjectProperty(None)
    new_txt = ObjectProperty(None)
    def add_input(self):
        txt_hld = self.ids.text_holder
        if self.new_txt == None:
            self.new_txt = TextInput()
            txt_hld.add_widget(self.new_txt)
        else:
            self.new_txt.focus = False
            print(self.new_txt.focus)
            self.new_txt = TextInput(focus = True)
            print(self.new_txt.focus)
            txt_hld.add_widget(self.new_txt)
    def que_txt_input(self, instance):
        self.which_txt = instance
        print(instance)
    def del_txt_input(self):
        print(self.which_txt)

class theNoteApp(App):
    title = 'My Notes'
    def build(self):
        return Notation()

if __name__ == '__main__':
    theNoteApp().run()


Desired Result:

I want to start typing after adding a new TextInput and after clicking in another widget I want the TextInput to loose focus and fire a unfocus_on_touch event?


Solution

  • I had the same problem some time ago and I opened an issue at kivy's github page. There is no solution yet, but there is a workaround. You have to add these lines to your TextInput rule:

    keyboard_mode: 'managed'
    keyboard_on_key_down: self.show_keyboard()
    

    After that, its working, but with the way you add the widgets you keep focus to all of them all the time, so you have to fix this independently.
    The only focus that you need is at your TextInput rule, nowhere else..