The handler of 'insert-text' is expected to update the value received in the position parameter (which we have seen in incorrect) to reflect the position from which future text should be inserted and return it. This is important so the cursor is changed to the right place after the signal handler returns (this is done by gtk
). If you don't update and return then the cursor remains at position 0.
After following the suggestion of using entry.get_position()
to obtain the right position value I found out that the update and return of position in my handler was being ignored by pygobject
. It behaved as if I was not returning anything (the cursor remained at position 0). Setting the position inside the handler did not help, because gtk
would change it back again to 0 after the handler returned.
After some further investigation I learned that the issue lies with the handling of in/out parameters in pygobject
which works well in most cases but not with signals (see bug 644927)
If you use connect to attach a handler to the signal and the signal has an in/out parameter you may not receive what you expect in the handler and even if you return a value this value will probably not be handled correctly by pygobject
either. Anything that depends on that value will probably not work as expected (e.g. advance the cursor to the new position)
There is a solution though which is to override the associated vfunc (the default handler) instead of connecting with connect()
. This solution implies deriving from the base class but it does work.
You can use this method for input validation/transformation on Gtk.Entry
. An example handling my use case would be:
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()
In this case the position parameter is received correctly and the return value is seen and used by pygobject so the cursor is correctly positioned.
Important Note
You have to inherit from Gtk.Editable in addition to Gtk.Entry. If you do not do so you will start seeing the validation or whatever you do inside do_insert_text
applying to every other Gtk.Entry
in your application. If you do not inherit you are overriding the base implementation provided by Gtk.Editable which is called by all other Gtk.Entry
widgets in your application. By inheriting from Gtk.Editable you override only the 'local' copy of the base implementation which only applies to your custom class.
entry.get_position()
. To which example in the documentation are you referring by the way? – Kristoferentry.get_posisition()
does the job I think so I will probably use that. – RaquelWarning: g_value_get_int: assertion 'G_VALUE_HOLDS_INT (value)' failed Gtk.main()
– Raquel