QComboBox - filtering by typing



  • Hi!

    Does exist working example of app:
    QComboBox with filtering items by typing in lineedit
    ?
    Filtering by "contain", not only by first symbols.

    Don't propose LineEdit, plz. I'm interested in QComboBox, because I'd like to select item from drop-down list with possibility of filtering.



  • @michaeldev
    Do you mean: typing into the QComboBox's line edit and having it select corresponding item(s) in the selection list?

    EDIT Oh, I see you've edited your question:

    Filtering by "contain", not only by first symbols.

    I don't know whether there's a better way now, but http://www.qtcentre.org/threads/23143-Combobox-entries-filter-as-I-type [from 2009!] is the same question with a solution using QSortFilterProxyModel.....



  • @JonB Doesn't work.


  • Lifetime Qt Champion

    Hi,

    doesn't work is a bit too vague.


  • Qt Champions 2017

    @michaeldev
    Besides, it does work :)
    and can use wildcards so its like a contain.
    Code directly used from @JonBs link.
    However, it can crash when connected directly to TextChanged as filtering and typing interfere and TextChanged triggered while filtering. it seems.
    Didnt really debug into it. However, using edit for filter string just works.

    alt text)



  • This post is deleted!


  • @SGaist said in QComboBox - filtering by typing:

    Hi,

    doesn't work is a bit too vague.

    Did you check that code?


  • Qt Champions 2017

    Hi @michaeldev

    as you can see two posts above @mrjj tested it for you and it works.

    So would you please tell us what's not working for you?

    Regards



  • @aha_1980 said in QComboBox - filtering by typing:

    Hi @michaeldev

    as you can see two posts above @mrjj tested it for you and it works.

    So would you please tell us what's not working for you?

    Regards

    I wrote "Don't propose LineEdit".

    Interesting, filtering works by first symbols (without additional QLineEdit), but doesn't work by "containing".


  • Qt Champions 2017

    @michaeldev

    don't propose != doesn't work

    every combo box includes a line edit, so you can do the filtering within the combo box if you adopt the example.

    you cannot expect us to write your code, we just suggest and help. for free! it's up to you to want our help or not.


  • Qt Champions 2017

    @michaeldev
    the lineedit is not important. its just that
    the sample would die from recursive calls as we
    would filter and type at same time and trigger signal, that trigger filter that trigger signal etc so
    i just use lineEdit for input as not to waste time to find out what signal to use instead to fix the sample or why
    rapid change of input would make it crash in its own lists. or what ever it was.

    it does work fine otherwise finding any combination of wildcards i tried.

    I expected you to put a debugger to it and see what is going on. :)



  • Right now my code :

    #ifndef MYCOMBOBOX_H
    #define MYCOMBOBOX_H
    
    #include <QComboBox>
    #include <QtSql>
    
    class MyComboBox : public QComboBox
    {
    
        Q_OBJECT
    
    public:
        explicit MyComboBox(QWidget *parent);
        virtual void showPopup();
        void focusOutEvent(QFocusEvent* event);
        void init(const QSqlRelationalTableModel *model,
                  const int idx,
                  const QString &relFiled);
    
    private:
        int relFieldIdx;
    };
    
    #endif // MYCOMBOBOX_H
    
    
    #include "mycombobox.h"
    
    #include <QCompleter>
    #include <QApplication>
    
    MyComboBox::MyComboBox(QWidget *parent) :
        QComboBox(parent)
    {
    }
    
    //Better do this in constructor, but - file ui
    void MyComboBox::init(const QSqlRelationalTableModel *model,
                          const int idx,
                          const QString &relFiled)
    {
        QSqlTableModel *relModel = model->relationModel(idx);
    
        relFieldIdx = relModel->fieldIndex(relFiled);
    
        setModel(relModel);
        setModelColumn(relFieldIdx);
        setEditable(false);
    }
    
    void MyComboBox::showPopup()
    {
        setEditable(true);
    
        QCompleter *completer = new QCompleter(model(), this);
        completer->setCompletionMode(QCompleter::PopupCompletion);
        completer->setCompletionColumn(relFieldIdx);
        setCompleter(completer);
    
        QComboBox::showPopup();
    }
    
    void MyComboBox::focusOutEvent(QFocusEvent* event) {
    
        //This code (probably) should be done differently
        if ((QApplication::focusWidget() != this) && (QApplication::focusWidget() != view()))
            setEditable(false);
        //
    
        QComboBox::focusOutEvent(event);
    }
    
    

    I don't have filtering by typing "by containing", only "by first symbols". But there is only one widget - MyComboBox. Maybe later I will make filtering in "God's regime ))
    Using - first call init(...)



  • Does this do what you want?

    #include <QApplication>
    #include <QStringListModel>
    #include <QPushButton>
    #include <QComboBox>
    #include <QSortFilterProxyModel>
    
    int main(int argc, char **argv) {
      QApplication app(argc, argv);
      QStringList modleList;
      for(int i=1;i<1000;++i)
      modleList <<  QStringLiteral("%1%2").arg(QLatin1Char('a'+(i%26))).arg(i,3,10,QLatin1Char('0'));
      QStringListModel model(modleList);
      QSortFilterProxyModel filterModel;
      filterModel.setSourceModel(&model);
      QComboBox w;
      w.setModel(&filterModel);
      w.setEditable(true);
      w.setCompleter(nullptr);
      QObject::connect(&w, &QComboBox::editTextChanged, &filterModel, [&filterModel](const QString& input){filterModel.setFilterRegExp('^'+input);},Qt::QueuedConnection);
      w.show();
      app.exec();
      return 0;
    }
    


  • @VRonin said in QComboBox - filtering by typing:

    Does this do what you want?

    #include <QApplication>
    #include <QStringListModel>
    #include <QPushButton>
    #include <QComboBox>
    #include <QSortFilterProxyModel>
    
    int main(int argc, char **argv) {
      QApplication app(argc, argv);
      QStringList modleList;
      for(int i=1;i<1000;++i)
      modleList <<  QStringLiteral("%1%2").arg(QLatin1Char('a'+(i%26))).arg(i,3,10,QLatin1Char('0'));
      QStringListModel model(modleList);
      QSortFilterProxyModel filterModel;
      filterModel.setSourceModel(&model);
      QComboBox w;
      w.setModel(&filterModel);
      w.setEditable(true);
      w.setCompleter(nullptr);
      QObject::connect(&w, &QComboBox::editTextChanged, &filterModel, [&filterModel](const QString& input){filterModel.setFilterRegExp('^'+input);},Qt::QueuedConnection);
      w.show();
      app.exec();
      return 0;
    }
    

    There isn't filtration by content. Am I wrong?


  • Qt Champions 2017

    Looking at the code I'm pretty sure there is. Have you actually loaded it in your IDE and given it a try?



  • @kshegunov said in QComboBox - filtering by typing:

    Looking at the code I'm pretty sure there is. Have you actually loaded it in your IDE and given it a try?

    Of course.



  • @michaeldev said in QComboBox - filtering by typing:

    There isn't filtration by content. Am I wrong?

    What does the line:

      QObject::connect(&w, &QComboBox::editTextChanged, &filterModel, [&filterModel](const QString& input){filterModel.setFilterRegExp('^'+input);},Qt::QueuedConnection);
    

    do?



  • @JonB said in QComboBox - filtering by typing:

    @michaeldev said in QComboBox - filtering by typing:

    There isn't filtration by content. Am I wrong?

    What does the line:

      QObject::connect(&w, &QComboBox::editTextChanged, &filterModel, [&filterModel](const QString& input){filterModel.setFilterRegExp('^'+input);},Qt::QueuedConnection);
    

    do?

    Have you actually loaded it in your IDE and given it a try?



  • @michaeldev
    No, I don't have an IDE or a C++ compiler.


  • Qt Champions 2017

    @michaeldev said in QComboBox - filtering by typing:

    Have you actually loaded it in your IDE and given it a try?

    I have and it works. There a couple of GUI tweaks to be done to it, which I imagine are left to you, however the example is functional!



  • @kshegunov said in QComboBox - filtering by typing:

    @michaeldev said in QComboBox - filtering by typing:

    Have you actually loaded it in your IDE and given it a try?

    I have and it works. There a couple of GUI tweaks to be done to it, which I imagine are left to you, however the example is functional!

    Thanks a lot. Даже так: спасибо, друг! ))



  • @VRonin said in QComboBox - filtering by typing:

    Does this do what you want?

    #include <QApplication>
    #include <QStringListModel>
    #include <QPushButton>
    #include <QComboBox>
    #include <QSortFilterProxyModel>
    
    int main(int argc, char **argv) {
      QApplication app(argc, argv);
      QStringList modleList;
      for(int i=1;i<1000;++i)
      modleList <<  QStringLiteral("%1%2").arg(QLatin1Char('a'+(i%26))).arg(i,3,10,QLatin1Char('0'));
      QStringListModel model(modleList);
      QSortFilterProxyModel filterModel;
      filterModel.setSourceModel(&model);
      QComboBox w;
      w.setModel(&filterModel);
      w.setEditable(true);
      w.setCompleter(nullptr);
      QObject::connect(&w, &QComboBox::editTextChanged, &filterModel, [&filterModel](const QString& input){filterModel.setFilterRegExp('^'+input);},Qt::QueuedConnection);
      w.show();
      app.exec();
      return 0;
    }
    

    This code does. After changing filtering code to

    filterModel.setFilterRegExp(QRegExp(input, Qt::CaseInsensitive, QRegExp::FixedString))
    

    I have situation nearly to my target. Why "nearly" : I have to press twice filtering symbol in edit. After first pressing - all item appears in edit. And list are being filtered by this item, so - only one item in list. After second pressing - everything is OK. There are filter substring in edit and appropriate items in list.


  • Lifetime Qt Champion

    @JonB said in QComboBox - filtering by typing:

    @michaeldev said in QComboBox - filtering by typing:

    There isn't filtration by content. Am I wrong?

    What does the line:

      QObject::connect(&w, &QComboBox::editTextChanged, &filterModel, [&filterModel](const QString& input){filterModel.setFilterRegExp('^'+input);},Qt::QueuedConnection);
    

    do?

    It connects the editTextChanged signal to a lambda to which a reference to filterModel is passed (the content of the square brackets), that will be called with a QString parameter (matching the signature of the signal). The lambda body updates the regular expression used by filterModel.



  • @SGaist said in QComboBox - filtering by typing:

    @JonB said in QComboBox - filtering by typing:

    @michaeldev said in QComboBox - filtering by typing:

    There isn't filtration by content. Am I wrong?

    What does the line:

      QObject::connect(&w, &QComboBox::editTextChanged, &filterModel, [&filterModel](const QString& input){filterModel.setFilterRegExp('^'+input);},Qt::QueuedConnection);
    

    do?

    It connects the editTextChanged signal to a lambda to which a reference to filterModel is passed (the content of the square brackets), that will be called with a QString parameter (matching the signature of the signal). The lambda body updates the regular expression used by filterModel.

    It's clear.



  • @SGaist
    My question was purely a rhetorical one! In reply to @michaeldev's

    There isn't filtration by content. Am I wrong?

    I was trying to draw his attention to the connect() line with the lambda containing the regular expression as doing the filtering when he said he couldn't see anything which would be doing that.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.