【问题标题】:Kivy - TextInput on_focus behavior issueKivy - TextInput on_focus 行为问题
【发布时间】:2016-04-26 03:33:51
【问题描述】:

我正在使用 kivy 创建一个应用程序。所以我认为我没有正确理解 FloatInput 的 on_focus 行为。

让我先描述一下我想在这里做什么。当用户单击 TextInput 时,我试图激活一个弹出小键盘(这个小键盘只有数字 0-9 的按钮和一个“输入”按钮)。接下来,一旦用户在弹出小键盘中输入数字并点击“输入”按钮,弹出窗口应该关闭并且 TextInput 的文本字段应该更新为用户输入的数字。

但是,我遇到了问题。本质上,我有一个包含多个如上所述构造的 TextInput 的表单(我将在下文中将它们称为“FloatInputs”b/c,这就是我给它们命名的)。我第一次将值输入其中一个 FloatInputs 时,一切都按预期工作。但是每当我尝试在第二个 FloatInput 中输入一个数字时,就会出现问题。具体来说,on_focus 函数被调用了两次,结果用户必须在弹出窗口中输入两次值(这显然不理想,因为它会使用户感到沮丧)。

如果这是一个愚蠢的问题,我深表歉意,但我已经对此感到困惑了很长一段时间。我认为问题的核心在于 TextInput 和弹出小部件的聚焦顺序,但我在这里可能错了。如果有人可以就如何修复此错误提供建议,我将不胜感激。

这里是相关的python代码:

class FloatInput(TextInput):

    def on_focus(self, instance, value):

        print 'ON FOCUS CALLED - THIS SHOULD ONLY BE CALLED ONCE!'

        # Adding this helped part of the problem (however, on_focus is still being called twice???)
        self.unfocus_on_touch = False

        prompt_content = BoxLayout(orientation='vertical')      # Main layout

        num_pad = NumPadWidget()
        prompt_content.add_widget(num_pad)

        def my_callback(instance):

            self.text = num_pad.ids.num_label.text
            self.popup.dismiss()

        # Now define the popup, with the content being the layout:
        self.popup = Popup(id='num_pad_popup', title='Enter value', content=prompt_content, size_hint=(0.8,0.5), autodismiss=False)

        num_pad.ids.enter_btn.bind(on_press=my_callback)

        # Open the pop-up:
        self.popup.open()

这里是相关的kv代码:

<NumPadButton@Button>:
    font_size: '16dp'
    bold: True

<NumPadWidget>:
    BoxLayout:
        orientation: 'vertical'
        BoxLayout:
            size_hint_y: 1
            id: num_label
            Label:
                id: num_label
                text: ''
        BoxLayout:
            size_hint_y: 5
            orientation: 'vertical'
            BoxLayout:
                NumPadButton:
                    text: '7'
                    on_press:
                        num_label.text = num_label.text + '7'
                NumPadButton:
                    text: '8'
                    on_press:
                        num_label.text = num_label.text + '8'
                NumPadButton:
                    text: '9'
                    on_press:
                        num_label.text = num_label.text + '9'
            BoxLayout:
                NumPadButton:
                    text: '4'
                    on_press:
                        num_label.text = num_label.text + '4'
                NumPadButton:
                    text: '5'
                    on_press:
                        num_label.text = num_label.text + '5'
                NumPadButton:
                    text: '6'
                    on_press:
                        num_label.text = num_label.text + '6'
            BoxLayout:
                NumPadButton:
                    text: '1'
                    on_press:
                        num_label.text = num_label.text + '1'
                NumPadButton:
                    text: '2'
                    on_press:
                        num_label.text = num_label.text + '2'
                NumPadButton:
                    text: '3'
                    on_press:
                        num_label.text = num_label.text + '3'
            BoxLayout:
                NumPadButton:
                    text: '0'
                    on_press:
                        num_label.text = num_label.text + '0'
                NumPadButton:
                    text: '.'
                    on_press:
                        num_label.text = num_label.text + '.'
                NumPadButton:
                    text: 'del'
                    on_press:
                        num_label.text = num_label.text[:-1]
            BoxLayout:
                BoxLayout:
                    size_hint_x: 1
                    NumPadButton:
                        text: 'C'
                        on_press:
                            num_label.text = ''
                BoxLayout:
                    size_hint_x: 2
                    NumPadButton:
                        id: enter_btn
                        text: 'Enter'

【问题讨论】:

  • 第一句应该以 TextInput 而不是 FloatInput 结尾。对于造成的混乱,我深表歉意。

标签: python kivy


【解决方案1】:

好吧,在玩了这个之后,我找到了一个解决方案来实现我想要的功能。但是,需要明确的是,这确实解决了 on_focus 行为以我在原始帖子中描述的方式运行的原因。

如果有人感兴趣,这里有一个解决方法:

class FloatInput(TextInput):

    def __init__(self, **kwargs):
        super(FloatInput, self).__init__(**kwargs)

    def on_touch_down(self, touch):
        if self.collide_point(touch.x, touch.y):

            prompt_content = BoxLayout(orientation='vertical')      # Main layout

            num_pad = NumPadWidget()
            prompt_content.add_widget(num_pad)

            def my_callback(instance):
                self.text = num_pad.ids.num_label.text
                self.popup.dismiss()

            # Now define the popup, with the content being the layout:
            self.popup = Popup(id='num_pad_popup', title='Enter value', content=prompt_content, size_hint=(0.8,0.5), autodismiss=False)
            num_pad.ids.enter_btn.bind(on_press=my_callback)

            # Open the pop-up:
            self.popup.open()

具体来说,此解决方案通过使用 on_touch_down 而不是寻找 TextInput 的焦点来工作。此外,使用“if self.collide_point(touch.x, touch.y)”查找碰撞可以防止所有相同类型的小部件都响应用户触摸的错误。

我希望这对某人有帮助!

【讨论】:

  • 在最近的构建中,使用两个参数调用 on_touch_down 方法。第一个位置参数(除 self 之外)是发生触摸的对象实例。其中第二个参数是触摸事件对象。
  • 如果你消费了触摸事件,那么我猜你应该返回 True 来停止传播。
  • 您能否提供完整的工作代码,以便我看到您描述的功能?我有一个类似的问题,想看看它如何与我的应用程序集成。谢谢。
【解决方案2】:

不管怎样,TextInput 的 on_focus() 方法如下所示:

def on_focus(self, instance, value, *largs):

如果值为 True,则为焦点事件。如果它是 False,那么它是一个散焦/模糊事件。我真的不知道他们为什么对这两个事件都使用一个处理程序,但他们以这种方式实现了它。我认为其他任何人都会将其实现为 on_focus()/on_blur()。

这可能是一个方法可能会触发两次的原因。

【讨论】:

  • 我终于找到了在我的应用程序中发生这么多奇怪事情的原因!应该创建一个 if 值 ... else ... 代码块,并将应该在焦点上运行的代码放入 if 部分,并将前一个小部件上应该发生的事情放在 else 部分散焦。
【解决方案3】:

在单击文本输入后尝试调用模式时,我遇到了类似的问题。如果我尝试使用on_focus,它会触发两次。对我有用的是设置is_focusable = False 并使用on_touch_down 事件来触发函数。

【讨论】:

    【解决方案4】:

    确保您的所有 TextInputs(在您的情况下为“FloatInput”)尽快在您的代码中将小部件属性 unfocus_on_touch 设置为 False。这意味着在 kv 文件中,工厂构建器字符串(如下)或一些包装的 __init__ 类函数。在 on_focus 事件中设置此属性为时已晚,可能会导致它被触发两次。

    Builder.load_string('''
    <RootWidget>:
        TextInput:
            unfocus_on_touch: False
            id: id_textbox
            text: 'hello world'
            multiline: False
            font_size: 20
    ''')
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2016-08-27
      • 2013-09-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-11-03
      • 2016-01-15
      相关资源
      最近更新 更多