Autocomplete textbox for multiple keywords/tags entry in PySide

Last month I started writing QTodoTxt, a PySide (Python Qt bindings) GUI for the todo.txt concept.

While using it for my own todo list I noticed several features that were missing (I intend to implement them all in due time), one of these features was auto-completion for projects and contexts when editing or creating a new task, something like this:


After some googling I found the built-in QCompleter component that can be easily attached to any QLineEdit control and allow easy auto-completion:

  lineEdit = QtGui.QLineEdit()
  completer = QtGui.QCompleter(
      ['one', 'two', 'three', 'four'])
  lineEdit.setCompleter(lineEdit)

However, this only allows auto-completing for the first word and I wanted to auto-completion for every word in the text. So I went back to google and found a post in the Qt developers forum that shows a simple implementation of this in C++.

Instead of using the QLineEdit's "setCompleter" method (which wasn't available for QTextEdit he was using), his implementation handles opening the completer manually and just attaches the completer to the QLineEdit using the QCompleter.setWidget method.

To create my own auto-complete control I implemented his C++ control in python and added some extra features of my own. At first I created the AutoCompleteEdit class that inherits from QLineEdit and initializes the QCompleter:

from PySide import QtCore, QtGui

class AutoCompleteEdit(QtGui.QLineEdit):
  def __init__(self, model, separator = ' ', \
      addSpaceAfterCompleting = True):
    super(AutoCompleteEdit, self).__init__()
    self._separator = separator
    self._addSpaceAfterCompleting = \
        addSpaceAfterCompleting
    self._completer = QtGui.QCompleter(model)
    self._completer.setWidget(self)
    self.connect(
        self._completer,
        QtCore.SIGNAL('activated(QString)'),
        self._insertCompletion)
    self._keysToIgnore = [QtCore.Qt.Key_Enter,
                          QtCore.Qt.Key_Return,
                          QtCore.Qt.Key_Escape,
                          QtCore.Qt.Key_Tab]


I overrid the keyPressEvent method of QLineEdit to handle the completion manually:

  def keyPressEvent(self, event):
    if self._completer.popup().isVisible():
      if event.key() in self._keysToIgnore:
        event.ignore()
        return
    super(AutoCompleteEdit, self).keyPressEvent(event)
    completionPrefix = self.textUnderCursor()
    if completionPrefix != self._completer.completionPrefix():
      self._updateCompleterPopupItems(completionPrefix)
    if len(event.text()) > 0 and len(completionPrefix) > 0:
      self._completer.complete()
    if len(completionPrefix) == 0:
      self._completer.popup().hide()

This method performs the following tasks:
  • If the user pressed Enter, Escape or Tab the method ignores them and returns.
  • Every other character is forwarded to the base method.
  • Filters the items displayed in the completer popup to only show the items that start with the text the user started to write (the completion prefix).

Thank you for reading,
You can see the full code in my Bitbucket repository: https://bitbucket.org/3david/qtodotxt/src/ec1e74eef575/qtodotxt/ui/controls/autocomplete_lineedit.py

Please feel free to leave comments,

David.

Comments

Manikandan said…
looks interesting... Thanks for the post! I'll try it out...
steven said…
thanks for this bit of code, i was looking for something like this for my own launcher
Phill said…
Hi David,

I would like to use your code in an opensource project. Is there any restrictions on modifying and reusing your code?

Thanks for such a grate post!
David said…
Hi Phill,

QTodoTxt was released under the GPL license: https://bitbucket.org/3david/qtodotxt/src/7ed26a155cb0da5543b781ae729e2b893be4dab3/gpl.txt?at=default

Anyway, you can use the code as you please (I would appreciate an attribution...)

David.
Matthieu said…
Hi David !

I would like to implement some new features in QTodoTxt (utf8, due date,...).

Is the development still active or is it better to fork and continue from my own repo ?

Matthieu
David Elentok said…
Hi Matthieu,

I've stopped working on QTodoTxt,
I've started working on an interactive vim plugin for todo.txt files,

feel free to fork :-)

David.
Rahul Mishra said…
Geninus,

This is exactly what I was looking for.

million thanks :)

Rahul

Popular posts from this blog

Restart the Windows File Sharing Service to fix weird problems

WPF, ImageSource and Embedded Resources

SharpDevelop dark color scheme