I'm using Qt4.6 and I have a QComboBox with a QCompleter in it.
The usual functionality is to provide completion hints (these can be in a dropdown rather than inline - which is my usage) based on a prefix. For example, given
chicken soup
chilli peppers
grilled chicken
entering ch
would match chicken soup
and chilli peppers
but not grilled chicken
.
What I want is to be able to enter ch
and match all of them or, more specifically, chicken
and match chicken soup
and grilled chicken
.
I also want to be able to assign a tag like chs
to chicken soup
to produce another match which is not just on the text's content. I can handle the algorithm but,
Which of QCompleter's functions do I need to override?
I'm not really sure where I should be looking...
Based on @j3frea suggestion, here is a working example (using
PySide
). It appears that the model needs to be set every timesplitPath
is called (setting the proxy once insetModel
doesn't work).Use
filterMode : Qt::MatchFlags
property. This property holds how the filtering is performed. If filterMode is set toQt::MatchStartsWith
, only those entries that start with the typed characters will be displayed.Qt::MatchContains
will display the entries that contain the typed characters, andQt::MatchEndsWith
the ones that end with the typed characters. Currently, only these three modes are implemented. Setting filterMode to any otherQt::MatchFlag
will issue a warning, and no action will be performed. The default mode isQt::MatchStartsWith
.This property was introduced in Qt 5.2.
Access functions:
You can get around QTBUG-7830 as mentioned above by providing custom role and making completion on that role. In the handler of that role, you can do the trick to let QCompleter know that item is there. This will work if you also override filterAcceptsRow in your SortFilterProxy model.
Building on the answer of @Bruno, I am using the standard
QSortFilterProxyModel
functionsetFilterRegExp
to change the search string. In this way no sub-classing is necessary.It also fixes a bug in @Bruno's answer, which made the suggestions vanish for some reasons once the input string got corrected with backspace while typing.
Update:
I figured that my previous solution worked until the string in the combobox matched none of the list items. Then the
QFilterProxyModel
was empty and this in turn reseted thetext
of the combobox. I tried to find an elegant solution to this problem, but I ran into problems (referencing deleted object errors) whenever I tried to change something onself.filterProxyModel
. So now the hack is to set the model ofself.filterProxyModel
everytime new when its pattern is updated. And whenever the pattern does not match anything in the model anymore, to give it a new model that just contains the current text (akapath
insplitPath
). This might lead to performance issues if you are dealing with very large models, but for me the hack works pretty well.Update 2:
I realized that this is still not the perfect way to go, because if a new string is typed in the combobox and the user presses enter, the combobox is cleared again. The only way to enter a new string is to select it from the drop down menu after typing.
Update 3:
Now enter works as well. I worked around the reset of the combobox text by simply taking it off charge when the user presses enter. But I put it back in, so that the completion functionality remains in place. If the user decides to do further edits.
Unfortunately, the answer is currently that it's not possible. To do that you'd need to duplicate much of the functionality of QCompleter in your own application (Qt Creator does that for its Locator, see
src/plugins/locator/locatorwidget.cpp
for the magic if you're interested).Meanwhile you could vote on QTBUG-7830, which is about making it possible to customize the way completion items are matched, like you want. But don't hold your breath on that one.
Thanks Thorbjørn, I actually did solve the problem by inheriting from
QSortFilterProxyModel
.The
filterAcceptsRow
method must be overwritten and then you just return true or false depending on whether or not you want that item displayed.The problem with this solution is that it only hides items in a list and so you can never rearrange them (which is what I wanted to do to give certain items priority).
[EDIT]
I thought I'd throw this into the solution since it's [basically] what I ended up doing (because the above solution wasn't adequate). I used http://www.cppblog.com/biao/archive/2009/10/31/99873.html: