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

R. *_*ruz 5 python gtk pygobject python-3.x gtk3

我在管理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()
Run Code Online (Sandbox Code Playgroud)

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

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

R. *_*ruz 7

"insert-text"的处理程序应该更新position参数(我们在不正确的情况下看到)中收到的值,以反映应该插入未来文本的位置并将其返回.这很重要,因此在信号处理程序返回后,光标会更改到正确的位置(这是由完成的gtk).如果不更新并返回,则光标保持在位置0.

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

在进行了一些进一步的调查之后,我了解到问题在于输入/输出参数的处理,pygobject在大多数情况下这些参数运行良好,但信号不是很好(参见bug 644927)

如果使用connect将处理程序附加到信号并且信号具有输入/输出参数,则可能无法在处理程序中收到您期望的内容,即使您返回一个值,该值也可能无法正确处理pygobject.依赖于该值的任何内容都可能无法按预期工作(例如,将光标前进到新位置)

虽然有一个解决方案是覆盖关联的vfunc(默认处理程序)而不是连接connect().这个解决方案意味着从基类派生但它确实有效.

您可以使用此方法进行输入验证/转换Gtk.Entry.处理我的用例的一个例子是:

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()
Run Code Online (Sandbox Code Playgroud)

在这种情况下,正确接收位置参数,并且pygobject可以看到并使用返回值,因此光标位置正确.

重要说明 除了Gtk.Entry之外,您还必须继承Gtk.Editable.如果您不这样做,您将开始看到验证或您在do_insert_text应用程序中的所有其他内容Gtk.Entry中执行的任何操作.如果您不继承,则覆盖Gtk.Editable提供的基本实现,该实现由Gtk.Entry应用程序中的所有其他小部件调用.通过继承自Gtk.Editable,您只覆盖仅适用于您的自定义类的基本实现的"本地"副本.