For example, the telephone format is +999 99 9999-9999
. That is, the GtkEntry
automatically add the characters (+,[space] and -) as the user types.
How to format the entries in Gtk.Entry
You could try having a validator. This old (2006) discussion can also be useful. –
Wigging
1. How to make an entry validator?
In order to do an entry validator in gtk, you need to connect the insert_text
signal to a validation method. It goes like so:
class EntryWithValidation(Gtk.Entry):
"""A Gtk.Entry with validation code"""
def __init__(self):
Gtk.Entry.__init__(self)
self.connect("insert_text", self.entryInsert)
def entryInsert(self, entry, text, length, position):
# Called when the user inserts some text, by typing or pasting.
# The `position` argument is not working as expected in Python
pos = entry.get_position()
# Your validation code goes here, outputs are new_text and new_position (cursor)
if new_text:
# Set the new text (and block the handler to avoid recursion).
entry.handler_block_by_func(self.entryInsert)
entry.set_text(new_text)
entry.handler_unblock_by_func(self.entryInsert)
# Can't modify the cursor position from within this handler,
# so we add it to be done at the end of the main loop:
GObject.idle_add(entry.set_position, new_pos)
# We handled the signal so stop it from being processed further.
entry.stop_emission("insert_text")
This code will generate a warning: Warning: g_value_get_int: assertion 'G_VALUE_HOLDS_INT (value)' failed Gtk.main()
because of the incapacity of handling return arguments in the Python bindings of Gtk signals. This question gives details about the bug. As suggested in the accepted answer, you can override the default signal handler like so:
class EntryWithValidation(Gtk.Entry, Gtk.Editable):
def __init__(self):
super(MyEntry, self).__init__()
def do_insert_text(self, new_text, length, position):
# Your validation code goes here, outputs are new_text and new_position (cursor)
if new_text:
self.set_text(new_text)
return new_position
else:
return position
2.The validation code
You now need to write the validation code. It is a bit fiddly since we need to place the cursor at the end of the inserted text but we may have added some extra characters while formatting.
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GObject
class TelNumberEntry(Gtk.Entry):
"""A Gtk.Entry field for phone numbers"""
def __init__(self):
Gtk.Entry.__init__(self)
self.connect("insert_text", self.entryInsert)
def entryInsert(self, entry, text, length, position):
pos = entry.get_position()
old_text = entry.get_text()
# Format entry text
# First we filter digits in insertion text
ins_dig = ''.join([c for c in text if c.isdigit()])
# Second we insert digits at pos, truncate extra-digits
new_text = ''.join([old_text[:pos], ins_dig, old_text[pos:]])[:17]
# Third we filter digits in `new_text`, fill the rest with underscores
new_dig = ''.join([c for c in new_text if c.isdigit()]).ljust(13, '_')
# We are ready to format
new_text = '+{0} {1} {2}-{3}'.format(new_dig[:3], new_dig[3:5],
new_dig[5:9], new_dig[9:13]).split('_')[0]
# Find the new cursor position
# We get the number of inserted digits
n_dig_ins = len(ins_dig)
# We get the number of digits before
n_dig_before = len([c for c in old_text[:pos] if c.isdigit()])
# We get the unadjusted cursor position
new_pos = pos + n_dig_ins
# If there was no text in the entry, we added a '+' sign, therefore move cursor
new_pos += 1 if not old_text else 0
# Spacers are before digits 4, 6 and 10
for i in [4, 6, 10]:
# Is there spacers in the inserted text?
if n_dig_before < i <= n_dig_before + n_dig_ins:
# If so move cursor
new_pos += 1
if new_text:
entry.handler_block_by_func(self.entryInsert)
entry.set_text(new_text)
entry.handler_unblock_by_func(self.entryInsert)
GObject.idle_add(entry.set_position, new_pos)
entry.stop_emission("insert_text")
if __name__ == "__main__":
window = Gtk.Window()
window.connect("delete-event", Gtk.main_quit)
entry = TelNumberEntry()
window.add(entry)
window.show_all()
Gtk.main()
Very good, your example works. But I'm getting the warning:
gtkentry_with_formation.py:62: Warning: g_value_get_int: assertion 'G_VALUE_HOLDS_INT (value)' failed Gtk.main()
–
Thant Glad it works. The warning is due to a bug in handling the position argument in Python. See this question: #38816194 –
Nagel
sorry to go back to that question. Why do you make double inheritance with
Gtk.Entry
and Gtk.Editable
, since Gtk.Entry
inherits from Gtk.Editable
? –
Thant This is to avoid overriding gtk.Editable implementation. See the answer to this question #38816194, the note at the bottom explains this in more detail. –
Nagel
© 2022 - 2024 — McMap. All rights reserved.