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: [code lang="python"]

gtkentrymulticompletion.py

author: Lawrence Oluyede

import pygtk pygtk.require(”2.0?) import gobject import gtk from gtk import gdk

class EntryMultiCompletion(gtk.Entry): def init(self): gtk.Entry.init(self) self.completion = gtk.EntryCompletion() # customize the matching function to match multiple space # separated words self.completion.set_match_func(self.match_func, None) # handle the match-selected signal, raised when a completion # is selected from the popup self.completion.connect(”match-selected”, self.on_completion_match) self.set_completion(self.completion)

def match_func(self, completion, key_string, iter, data):
    model = self.completion.get_model()
    # get the completion strings
    modelstr = model[iter][0]
    # check if the user has typed in a space char,
    # get the last word and check if it matches something
    if ” ” in key_string:
        last_word = key_string.split()[-1]
        return modelstr.startswith(last_word)
    # we have only one word typed
    return modelstr.startswith(key_string)

def on_completion_match(self, completion, model, iter):
    current_text = self.get_text()
    # if more than a word has been typed, we throw away the
    # last one because we want to replace it with the matching word
    # note: the user may have typed only a part of the entire word
    #       and so this step is necessary
    if ” ” in current_text:
        current_text = ” “.join(current_text.split()[:-1])
    # add the matching word
    current_text = “%s %s” % (current_text, model[iter][0])

    # set back the whole text
    self.set_text(current_text)
    # move the cursor at the end
    self.set_position(-1)

    # stop the event propagation
    return True

if name == “main”: # register the class as a Gtk widget gobject.type_register(EntryMultiCompletion)

win = gtk.Window()
win.connect(’delete-event’, gtk.main_quit)

entrycompl = EntryMultiCompletion()
liststore = gtk.ListStore(gobject.TYPE_STRING)
entrycompl.completion.set_model(liststore)
entrycompl.completion.set_text_column(0)
for word in [’abc’, ‘def’, ‘ghi’, ‘jkl’, ‘mno’,
             ‘pqr’, ’stu’, ‘vwx’, ‘yz’]:
    liststore.append([word])

win.add(entrycompl)
win.show_all()

gtk.main()

[/code]

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