inicio mail me! sindicaci;ón

PyGTK - EntryMultiCompletion

Recently I had to customize a bit the gtk.EntryCompletion widget to match against a list of word. The particularity of the needed customization is to have this widget display its popup everytime the user types in a new word, the words are separated by space.

So I dug around because I thought that the only way was to write a custom widget, but I immediately found a problem: there’s no documentation on writing custom widgets with PyGTK except for this: widget.py (in the pygtk cvs repository). Looking here and there I found myself in the GTK+ cvs repository reading this and this… but there was nothing there for me :-(

Oh good old C-days! :-D The solution (with the hint of Juhaz@#pygtk on irc.gimp.net) was a lot easier than I thought:

  1. # gtkentrymulticompletion.py
  2. # author: Lawrence Oluyede
  3. import pygtk
  4. pygtk.require(2.0?)
  5. import gobject
  6. import gtk
  7. from gtk import gdk
  8.        
  9. class EntryMultiCompletion(gtk.Entry):
  10.     def __init__(self):
  11.         gtk.Entry.__init__(self)
  12.         self.completion = gtk.EntryCompletion()
  13.         # customize the matching function to match multiple space
  14.         # separated words
  15.         self.completion.set_match_func(self.match_func, None)
  16.         # handle the match-selected signal, raised when a completion
  17.         # is selected from the popup
  18.         self.completion.connect(”match-selected”, self.on_completion_match)
  19.         self.set_completion(self.completion)
  20.        
  21.     def match_func(self, completion, key_string, iter, data):
  22.         model = self.completion.get_model()
  23.         # get the completion strings
  24.         modelstr = model[iter][0]
  25.         # check if the user has typed in a space char,
  26.         # get the last word and check if it matches something
  27.         if ” ” in key_string:
  28.             last_word = key_string.split()[-1]
  29.             return modelstr.startswith(last_word)
  30.         # we have only one word typed
  31.         return modelstr.startswith(key_string)
  32.        
  33.     def on_completion_match(self, completion, model, iter):
  34.         current_text = self.get_text()
  35.         # if more than a word has been typed, we throw away the
  36.         # last one because we want to replace it with the matching word
  37.         # note: the user may have typed only a part of the entire word
  38.         #       and so this step is necessary
  39.         if ” ” in current_text:
  40.             current_text = ” “.join(current_text.split()[:-1])
  41.         # add the matching word
  42.         current_text = “%s %s” % (current_text, model[iter][0])
  43.        
  44.         # set back the whole text
  45.         self.set_text(current_text)
  46.         # move the cursor at the end
  47.         self.set_position(-1)
  48.        
  49.         # stop the event propagation
  50.         return True
  51.        
  52. if __name__ == “__main__”:
  53.     # register the class as a Gtk widget
  54.     gobject.type_register(EntryMultiCompletion)
  55.        
  56.     win = gtk.Window()
  57.     win.connect(’delete-event’, gtk.main_quit)
  58.        
  59.     entrycompl = EntryMultiCompletion()
  60.     liststore = gtk.ListStore(gobject.TYPE_STRING)
  61.     entrycompl.completion.set_model(liststore)
  62.     entrycompl.completion.set_text_column(0)
  63.     for word in [’abc’, ‘def’, ‘ghi’, ‘jkl’, ‘mno’,
  64.                  ‘pqr’, ’stu’, ‘vwx’, ‘yz’]:
  65.         liststore.append([word])
  66.        
  67.     win.add(entrycompl)
  68.     win.show_all()
  69.        
  70.     gtk.main()

written on Python 2.4.1, PyGTK 2.6.1, GTK+ 2.6.4

It’s a bit hacky but it works!

update: fixed a couple of bugs and avoid the display of popup if the char is a space. Also, the thing it’s in the PyGTK FAQ, look: How do I insert a list of words (space separated) in a GtkEntry with the help of GtkEntryCompletion?

Related posts

  • PyAmazon plus PyGTK equals Amazon Client
  • Writing a Widget Using Cairo and PyGTK 2.8, Part 2
  • Writing a Widget Using Cairo and PyGTK 2.8
  • Writing a Widget Using Cairo and PyGTK 2.8
  • Writing a Widget Using Cairo and PyGTK 2.8, Part 2
  • Gravatar

    learning python » Blog Archive » Writing a Custom Widget Using PyGTK said,

    July 26, 2006 @ 3:01 am

    […] The three the most useful links that I found on this subject were: A song for the lovers, the writing a widget turotial on the PyGTK website, and the widget.py example in the PyGTK cvs. […]

    Gravatar

    Siva Chandran P said,

    January 12, 2007 @ 10:10 am

    There is small issue with the code. If you complete the first word by autocomplete then it won’t clear the partially typed chars. For example say you have “tea” “coffee” and “beer” as autocomplete item and if i type te then it will show the “tea” as popup. If i select the “tea” then it fills the entry by “te tea”.

    The follow lines can be modified to solve the problem Modify these lines if ” ” in current_text: current_text = ” “.join(current_text.split()[:-1])

    current_text = “%s %s” % (current_text, model[iter][0])

    to

    if ” ” in current_text: current_text = ” “.join(current_text.split()[:-1]) current_text = “%s %s” % (current_text, model[iter][0]) else: current_text = model[iter][0]
    Gravatar

    Lawrence said,

    January 12, 2007 @ 11:19 am

    Have a look at the version in the FAQ. It has changed a lot: http://www.async.com.br/faq/py.....14.024.htp

    RSS feed for comments on this post · TrackBack URI

    Leave a Comment