kivy TextInput 是否有焦点丢失事件调度程序?

Is there a focus lost event dispatcher for a kivy TextInput?

问题:

有没有办法在 multiline = True TextInput 失去焦点时触发事件?

背景:

我试过on_touch_up功能。但它 returns 我所有 TextInputs 的实例,而不仅仅是当前小部件。我尝试了 text_validate_unfocus = False,结果相同。

代码:

import kivy
kivy.require("1.10.1")

from kivy.app import App
from kivy.uix.floatlayout import FloatLayout
from kivy.properties import ObjectProperty, NumericProperty
from kivy.uix.textinput import TextInput
from kivy.uix.bubble import Bubble
from kivy.lang import Builder
from kivy.storage.jsonstore import JsonStore

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: ''
    foreground_color: (0,0.61,0.36,1) if self.focus else (0.71,0.75,0.71,1)
    unfocus_on_touch: False
    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:
        color: (0,0,0,1)
        pos_hint: {'top': 1, 'right': 0.9}
        size_hint: [0.1, None]
        height: Window.height / 15
        Image:
            source: 'gear_2.png'
            center_y: self.parent.center_y
            center_x: self.parent.center_x
            size: self.parent.width /1.5, self.parent.height/ 1.5
            allow_stretch: True
    Button:
        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()
        Image:
            source: 'plus_text12354.png'
            center_y: self.parent.center_y
            center_x: self.parent.center_x
            size: self.parent.width /1.5, self.parent.height/ 1.5
            allow_stretch: True
    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 TextInput(TextInput):
    got_txt = ObjectProperty(None)
    def on_touch_up(self, touch):
        if not self.collide_point(*touch.pos):
            self.text_validate_unfocus = False
            note = Notation()
            note.show_bubble
            self.got_txt=note.que_txt_input(self)
        return super(TextInput, self).on_touch_up(touch)
class Notation(FloatLayout):
    which_txt = ObjectProperty(None)
    new_txt = ObjectProperty(None)
    cnt = NumericProperty(0)
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.the_file=JsonStore('txt_input.json')
        self.cnt = self.the_file.count()
        lst = self.the_file.keys
    def add_input(self):
        txt_hld = self.ids.text_holder
        self.cnt += 1
        self.new_txt = TextInput(id=str(self.cnt))
        self.the_file.put(str(self.cnt), the_id=str(self.cnt), the_input='')
        txt_hld.add_widget(self.new_txt)
    def que_txt_input(self, instance):
        self.which_txt = instance
        print(instance.text, instance)
        return instance
    def del_txt_input(self):
        print(self.which_txt)
    def the_file(self, notestore):
        self.notestore = notestore
    def show_bubble(self):
        self.add_widget(ChoiceBubble())
    def get_store(self):
        the_keys = list(self.the_file.keys)
        print(the_keys)
        return the_keys

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

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

期望的结果:

失去焦点后,我想在 root class 的顶部添加一个气泡 widget。这将使用户可以选择将刚刚失去焦点的 TextInput id 和文本保存、加密或删除到 JSON 文件。

on_focus 事件将在焦点布尔值更改时触发。

I have tried on_touch_up function. But it returns the instances of all my TextInputs, not just the current widget.

这是因为您没有编写任何代码将其限制在您关心的小部件上,如果您愿意,可以这样做。

问题

  1. 对象的多个实例,Notation。一个来自 App class 中的 build() 方法 (return Notation()),另一个实例在 on_touch_up() 方法 (note = Notation()) 中创建,每当 on_touch_up 事件被触发。在 on_touch_up() 方法中创建的那些实例没有可见视图,即它不会显示在 window.
  2. AttributeError: 'ChoiceBubble' object has no attribute 'del_txt_input'
  3. ChoiceBubble 中的文本不可见,即默认文本颜色为白底白字。

解决方案

  1. 使用App.get_running_app().root获取实例化根。
  2. root.del_txt_input()替换为app.root.del_txt_input()
  3. color: 0, 0, 0, 1 添加到 class 规则,<Label>:
  4. 使用on_focus事件显示BubbleButton

片段 - kv

<Label>:
    color: 0, 0, 0, 1
    ...

<ChoiceBubble>:
    ...
    BubbleButton:
        text: 'Delete'
        on_release: app.root.del_txt_input()

片段 - py 文件

class TextInput(TextInput):
    got_txt = ObjectProperty(None)

    def on_focus(self, instance, value):
        if not value:   # defocused
            note = App.get_running_app().root
            note.show_bubble()
            self.got_txt = note.que_txt_input(self)

输出