[PyQt] Just for fun: QCompleter accessing a QListWidget's internal model through a "proxy" ?

fpp fpp.gsp at gmail.com
Tue Aug 17 19:23:55 BST 2010


Hi everyone,

After many moons of lurking I have finally subscribed to ask for
advice about my current challenge:

In this app I'm working on (my first "real", non-trivial one,
admittedly), I have a number of QListWidgets in the main window,
holding plain strings, each with an associated QLineEdit for input.
They work just fine, and there really is no need for anything more
elaborate than list widgets for what they do.

Only now that it's almost finished, with everything in place and the
code working well, I just discovered the existence of QCompleters by
accident... and obviously now I want them in the line edits.

However, QCompleters are designed to work only with "real" models, not
convenience widgets. Of course it's very easy to use them with a plain
QStringList, but it feels somewhat clunky and inefficient to duplicate
the list widget's content to the completer's string list, refreshing
it each time that content changes... and I don't really feel like
retooling the entire UI to use QListViews just for the sake of
completers.

So I thought, perhaps naively, that it might be possible to build a
kind of "proxy" model, that would feed a completer with data pulled
from a list widget's hidden, internal model.

After quite some time trying to make sense of the Qt docs (which seem
to contradict themselves sometimes), I settled on the following :

- make the model a subclass of QAbstractListModel;

- reimplement the rowCount(), data() and index() methods as required,
to fetch the relevant data from the list widget (passed as a parameter
to the constructor).

Here is the entire model code :

class proxyModel(QAbstractListModel):
    def __init__(self, qlwi, parent=None):
        QAbstractListModel.__init__(self, parent)
        self.qlwi = qlwi

    def index (self, row, col = 0, parent = None):
        return self.qlwi.indexFromItem(self.qlwi.item(row))

    def rowCount (self, parent = None):
        return self.qlwi.count()

    def data (self, index, role = Qt.DisplayRole):
        return self.qlwi.itemFromIndex(index).data(role)

I have verified (with good old "print"s) that the three methods return
the expected values and types (QModelIndex, int and QVariant),
reflecting changes made to the list widget on the fly.

Unfortunately, setting a completer's model to a proxyModel instance
does exactly nothing: everything works just as before, without
completion.

Lacking a better understanding of the Qt internals, I'm at a loss as
to which way I should dig now... I tried to Google for "prior art",
and found nothing relevant, which usually means one of two things :

- the entire notion is stupid and impossible, for some fundamental
reason that eludes me;

- or else it is actually so trivial that no one has ever thought of
documenting it, and I'm just missing something really obvious.

Either way, I'd welcome suggestions and pointers to the what and why,
hopefully learning something important about (Py)Qt in the process...

Thanks in advance,
fp


More information about the PyQt mailing list