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
-
@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".
-
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.
-
@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?
-
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. -
@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.
-
@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 byfilterModel
. -
@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 byfilterModel
.It's clear.
-
@SGaist
My question was purely a rhetorical one! In reply to @michaeldev'sThere 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. -
The best option I found is with QCompleter class
combo->setEditable(true); // make placeholder editable combo->setCurrentIndex(-1); // focus on placeholder combo->lineEdit()->setPlaceholderText("Enter keywords..."); combo->setInsertPolicy(QComboBox::NoInsert); // make QComboBox not insertable, but still editable combo->completer()->setCompletionMode(QCompleter::PopupCompletion); // popup list below with possible options combo->completer()->setCaseSensitivity(Qt::CaseInsensitive); combo->completer()->setFilterMode(Qt::MatchContains); // Finding any matches in text
-
come from py, with pyside6, the worked code should be:
from PySide6.QtWidgets import QComboBox, QCompleter, QWidget from PySide6.QtCore import Qt, QStringListModel class Selector(QComboBox): def __init__(self, item_list: list | tuple, parent: QWidget = None, filter: bool = True): super().__init__(parent) self.item_list = item_list self.setEditable(True); self.setInsertPolicy(self.InsertPolicy.NoInsert) self.addItems(item_list) if filter: completer = self._init_completer() self.setCompleter(completer) self.editTextChanged.connect(self.on_text_changed) def _init_completer(self) -> QCompleter: comp = QCompleter(self) comp.setFilterMode(Qt.MatchFlag.MatchContains) comp.setCompletionMode(QCompleter.CompletionMode.PopupCompletion) comp.setCaseSensitivity(Qt.CaseSensitivity.CaseInsensitive) return comp def on_text_changed(self, text): filtered_items = [item for item in self.item_list if text.lower() in item.lower()] model = QStringListModel(filtered_items, self) self.completer().setModel(model)
Referenced from @TENK228 code.
(this problem troubled me, a newer, for a few days.)