来自Gtk的插入文本信号上的Gtk 3位置属性。条目始终为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()
我在信号处理程序上收到的position属性始终为0。除非我误解了,否则它应该不是应该插入下一个文本的位置吗?
最后,我要做的是验证小部件中的文本输入,以限制将被接受的字符。我计划执行此操作的方式与文档中提供的示例相似,在该文档中,所有字符都转换为大写。
问题答案:
“插入文本”的处理程序应更新position参数中接收到的值(我们已经看错了),以反映将来应插入文本的位置并返回它。这一点很重要,因此在信号处理程序返回后将光标更改到正确的位置(这是通过完成的gtk
)。如果您不更新并返回,则光标将保持在位置0。
在遵循使用entry.get_position()
以获得正确位置值的建议之后,我发现忽略了处理程序中位置的更新和返回pygobject
。表现得好像我什么也不返回(光标停留在位置0)。设置处理程序内部的位置无济于事,因为gtk
在处理程序返回后会将其再次更改回0。
经过一些进一步的调查,我了解到问题在于输入/输出参数的处理pygobject
在大多数情况下都可以正常工作,但不适用于信号(请参见错误644927)
如果使用connect将处理程序附加到信号上,并且信号具有in /
out参数,则您可能不会在处理程序中收到期望的结果,即使您返回一个值,该值也可能不会被正确处理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()
在这种情况下,可以正确接收位置参数,并且pygobject可以看到并使用返回值,因此可以正确定位光标。
重要说明
除了Gtk.Entry,您还必须继承自Gtk.Editable。如果您不这样做,您将开始看到验证或您在do_insert_text
应用程序中对其他Gtk.Entry
应用程序所做的任何内部操作。如果不继承,则将覆盖Gtk.Editable提供的基本实现,该实现由Gtk.Entry
应用程序中的所有其他小部件调用。通过从Gtk.Editable继承,您仅覆盖基本实现的
“本地” 副本,该副本仅适用于您的自定义类。