来自 Gtk.Entry 的插入文本信号的 Gtk 3 位置属性始终为 0

Gtk 3 position attribute on insert-text signal from Gtk.Entry is always 0

我在管理 Gtk.Entry 小部件发出的插入文本信号时遇到问题。考虑以下示例:

from gi.repository import Gtk

def on_insert_text(entry, new_text, new_text_length, position):
    print(position)

entry = Gtk.Entry()
entry.connect('insert-text', on_insert_text)

window = Gtk.Window()
window.connect("destroy", lambda q: Gtk.main_quit())
window.add(entry)
window.show_all()
Gtk.main()

我在信号处理程序上收到的位置属性始终为 0。除非我误解了这不应该是应该插入下一个文本的位置吗?

最后我想做的是验证小部件中的文本输入以限制将被接受的字符。我打算这样做的方式类似于文档中提供的示例,其中所有字符都转换为大写。

'insert-text' 的处理程序应该更新位置参数中接收到的值(我们已经看到不正确)以反映未来文本应该插入的位置,return 它.这很重要,因此光标会更改到信号处理程序 return 之后的正确位置(这是由 gtk 完成的)。如果你不更新 return 那么光标会停留在位置 0.

在遵循使用 entry.get_position() 获取正确位置值的建议后,我发现 pygobject 忽略了处理程序中位置的更新和 return。它表现得好像我没有 returning 任何东西(光标保持在位置 0)。在处理程序中设置位置没有帮助,因为 gtk 会在处理程序 returned 之后再次将其更改回 0。

经过进一步调查后,我了解到问题出在 pygobject 中 in/out 参数的处理,这在大多数情况下效果很好,但信号却不行(参见 bug 644927

如果您使用 connect 将处理程序附加到信号并且该信号有一个 in/out 参数,您可能无法在处理程序中收到您期望的内容,即使您 return 一个值 这个值可能也不会被 pygobject 正确处理。任何依赖于该值的东西都可能无法按预期工作(例如将光标前进到新位置)

有一个解决方案是覆盖关联的 vfunc(默认处理程序)而不是与 connect() 连接。此解决方案意味着从基础派生 class 但它确实有效。

您可以使用此方法在 Gtk.Entry 上输入 validation/transformation。处理我的用例的示例是:

import re
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk


class MyEntry(Gtk.Entry, Gtk.Editable):

    def __init__(self):
        super(MyEntry, self).__init__()

    def do_insert_text(self, new_text, length, position):
        regexp = re.compile('^(\d*\.?\d*)$')

        if new_text == '.' and '.' in self.get_text():
            return position
        elif regexp.match(new_text) is not None:
            self.get_buffer().insert_text(position, new_text, length)
            return position + length

        return position

entry = MyEntry()
window = Gtk.Window()
window.connect("destroy", lambda q: Gtk.main_quit())
window.add(entry)
window.show_all()

Gtk.main()

在这种情况下,位置参数被正确接收并且 return 值被 pygobject 看到并使用,因此光标被正确定位。

重要提示 除了 Gtk.Entry 之外,您还必须继承 Gtk.Editable。如果您不这样做,您将开始看到验证或您在 do_insert_text 中所做的任何事情都适用于应用程序中的所有其他 Gtk.Entry。如果您不继承,您将覆盖 Gtk.Editable 提供的基础实现,它会被应用程序中的所有其他 Gtk.Entry 小部件调用。通过从 Gtk.Editable 继承,您仅覆盖仅适用于您的自定义 class.

的基本实现的 'local' 副本