Unsolved QComboBox value mapping
-
@JonB https://regex101.com is your friend when dealing with regular expression.
-
@SGaist
OK, so(?!...)
is "negative lookahead". I think you are filtering out items starting withtext
(why only starting with, I don't know). But thetext
might happen to contain reg ex special chars, and you're not escaping them? I'm just trying to understand.... -
In the case at hand, if text happened to contain such special characters, then yes it wouldn't be handle properly but it's then the responsibility of the author to handle that case if such an expression could be listed in the first combobox.
-
To avoid the problem @JonB correctly highlighted:
- create this class in a header file
class NegativeSortFilterProxyModel : public QSortFilterProxyModel{ Q_OBJECT Q_DISABLE_COPY(NegativeSortFilterProxyModel) public: explicit NegativeSortFilterProxyModel(QObject* parent = Q_NULLPTR) : QSortFilterProxyModel(parent){} protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const Q_DECL_OVERRIDE{ return !QSortFilterProxyModel::filterAcceptsRow(source_row,source_parent); } };
- in the snippet above replace
QSortFilterProxyModel
withNegativeSortFilterProxyModel
- replace
"^(?!"+text+".*)$"
with'^'+QRegExp::escape(text)+'$'
-
@SGaist said in QComboBox value mapping:
In the case at hand, if text happened to contain such special characters, then yes it wouldn't be handle properly but it's then the responsibility of the author to handle that case if such an expression could be listed in the first combobox.
OK, that clarifies, it was just that I was trying to confirm my understanding.
(I do not mean to be picky, or get into an argument. I understand this was example code now, and this is not a huge issue. I totally respect your excellent answers. But I do not agree that this should be written as "the responsibility of the author to handle that case if such an expression could be listed in the first combobox". Combobox could contain whatever. Your code --- given that it's picking up whatever happens to be in the other combo box to remove from this one --- should be responsible for whatever the Qt/C++/library is for going
QRegExp(text)::EscapeProtectChars()
instead of just passingtext
. IMHO.)replace
"^(?!"+text+".*)$"
with'^'+text+'$'
Although your suggestion makes the reg exp a bit easier to understand, I don't see that it "To avoid the problem @JonB correctly highlighted" (if you mean about
text
), in thattext
is still inserted into a reg exp without escape/protection.As I say, I don't mean to be picky/rude/disrespectful, I'm just trying to verify my understanding.
-
@JonB Sorry, I thought you were referring to another problem.
In my original implementation if you hadItem1
,Item2
, ... ,Item10
and selectItem1
,Item10
would disappear too.
i corrected the text above to do the regexp escaping too so now theNegativeSortFilterProxyModel
solution should be general.To put it all together:
class NegativeSortFilterProxyModel : public QSortFilterProxyModel{ Q_OBJECT Q_DISABLE_COPY(NegativeSortFilterProxyModel) public: explicit NegativeSortFilterProxyModel(QObject* parent = Q_NULLPTR) : QSortFilterProxyModel(parent){} protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const Q_DECL_OVERRIDE{ return !QSortFilterProxyModel::filterAcceptsRow(source_row,source_parent); } };
QStringListModel* comboModel=new QStringListModel(QStringList() << "Item1" << "Item2" << "Item3",this); NegativeSortFilterProxyModel* comboFilter = new NegativeSortFilterProxyModel(this); comboFilter->setSourceModel(comboModel); combo1->setModel(comboModel); combo2->setModel(comboFilter); connect(combo1, QOverload<const QString&>::of(&QComboBox::currentIndexChanged),comboFilter,[comboFilter](const QString &text)->void{comboFilter->setFilterRegExp('^'+QRegExp::escape(text)+'$');});
-
@VRonin said in QComboBox value mapping:
In my original implementation if you had Item1, Item2, ... , Item10 and select Item1, Item10 would disappear too.
Ah, yes indeed, I had asked/wondered why @SGaist's reg exp was a left-hand side match only, but nobody answered that, so I forgot about it. Again you have clarified my puzzlement by confirming it would have done a partial match by making yours a full match, so I am a happy understanding bunny now :)
-
If you are not dealing with a large number of items you could regenerate the contents of the second combobox excluding the selected item from the first combobox. Use the find option to make sure the same item is selected or active after rebuilding the list of combobox items (if the second combobox select happens to not match the first). You would iterate over the items in the first combobox and add them to the second excluding the one that is currently active.
If the are many items in the combobox you could use insert/delete (take) to add or remove items. It is a little more complicated to do this over the first method.
-
@Rondog Hi
In the project, i have to deal with 8-9 items only. Can you please share the code of regenerating the content of second combobox based upon the selection of item in first combobox. -
@VRonin Its working fine but not able to select item1in combobox1. If i want to select item1 then first have to selwct some other item in combobox1 then only it allows to selwct item1.
Kindly suggest on how can item1 be selected.Regards,
Anuj -
I can't reproduce, can you try this minimal example?
#include <QApplication> #include <QSortFilterProxyModel> #include <QStringListModel> #include <QComboBox> #include <QHBoxLayout> class NegativeSortFilterProxyModel : public QSortFilterProxyModel{ Q_DISABLE_COPY(NegativeSortFilterProxyModel) public: explicit NegativeSortFilterProxyModel(QObject* parent = Q_NULLPTR) : QSortFilterProxyModel(parent){} protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const Q_DECL_OVERRIDE{ return !QSortFilterProxyModel::filterAcceptsRow(source_row,source_parent); } }; int main(int argc, char *argv[]) { QApplication a(argc,argv); QWidget mainWid; QComboBox* combo1=new QComboBox(&mainWid); QComboBox* combo2=new QComboBox(&mainWid); QHBoxLayout* mainLay = new QHBoxLayout(&mainWid); mainLay->addWidget(combo1); mainLay->addWidget(combo2); QStringListModel* comboModel=new QStringListModel(QStringList() << "Item1" << "Item2" << "Item3",&mainWid); NegativeSortFilterProxyModel* comboFilter = new NegativeSortFilterProxyModel(&mainWid); QObject::connect(combo1, QOverload<const QString&>::of(&QComboBox::currentIndexChanged),comboFilter,[comboFilter](const QString &text)->void{comboFilter->setFilterRegExp('^'+QRegExp::escape(text)+'$');}); comboFilter->setSourceModel(comboModel); combo1->setModel(comboModel); combo2->setModel(comboFilter); mainWid.show(); return a.exec(); }