Nicest way to have QListWidgetItem with extra data?
-
I would like the experts' opinion on how I should implement the following in the "nicest" way....
I have a list of items to present to the user to choose from. The items just present text to the user, but --- as in many situations --- they also need a value (integer) associated with each item, which I will to retrieve when items are selected. So I start with a list of items (Python, not a
QList
, nor model rows, so we don't start from anything particular suitable for Qt) with text & value, like:"Some Item", 3 "Different", 4 ... "Another Item", 1
Now, if the list were single-selection, I would be using a
QComboBox
. That allows for items having aQVariant userData
, and nice functions like https://doc.qt.io/qt-5/qcombobox.html#itemData or https://doc.qt.io/qt-5/qcombobox.html#findData. I have used that elsewhere.The problem is that the list is multi-selection. That rules out
QComboBox
, and I do not wish to display with a table-type widget only showing one column, I wish to use a list-type widget. That has led me toQListWidget
&QListWidgetItem
. I then see about 3 ways I could store my data:-
Sub-class
QListWidgetItem
and store the value in an explicit member variable. -
Sub-class
QListWidgetItem
and store the value viaQListWidgetItem::setData()
with some role. (I'm not sure I actually need to sub-class here: I think I can just use that for my purpose on aQListWidgetItem
...?) -
Decide that I'd be better in this case moving to a
QListView
. Create a model with 2 columns (text & value), and useQListView::setModelColumn()
to display the text column.
Which would you do (and why)? My definition of "nicest" usually means "least lines of code for me to add", but for example if trying to use
QListWidget(Item)
for this is really pushing a round peg into a square hole I'm willing to move off that. -
-
I would like the experts' opinion on how I should implement the following in the "nicest" way....
I have a list of items to present to the user to choose from. The items just present text to the user, but --- as in many situations --- they also need a value (integer) associated with each item, which I will to retrieve when items are selected. So I start with a list of items (Python, not a
QList
, nor model rows, so we don't start from anything particular suitable for Qt) with text & value, like:"Some Item", 3 "Different", 4 ... "Another Item", 1
Now, if the list were single-selection, I would be using a
QComboBox
. That allows for items having aQVariant userData
, and nice functions like https://doc.qt.io/qt-5/qcombobox.html#itemData or https://doc.qt.io/qt-5/qcombobox.html#findData. I have used that elsewhere.The problem is that the list is multi-selection. That rules out
QComboBox
, and I do not wish to display with a table-type widget only showing one column, I wish to use a list-type widget. That has led me toQListWidget
&QListWidgetItem
. I then see about 3 ways I could store my data:-
Sub-class
QListWidgetItem
and store the value in an explicit member variable. -
Sub-class
QListWidgetItem
and store the value viaQListWidgetItem::setData()
with some role. (I'm not sure I actually need to sub-class here: I think I can just use that for my purpose on aQListWidgetItem
...?) -
Decide that I'd be better in this case moving to a
QListView
. Create a model with 2 columns (text & value), and useQListView::setModelColumn()
to display the text column.
Which would you do (and why)? My definition of "nicest" usually means "least lines of code for me to add", but for example if trying to use
QListWidget(Item)
for this is really pushing a round peg into a square hole I'm willing to move off that.hi @JonB
even so I personally don't do it, most of the time, option 3 is the way to go :)
Not the fastest, least amount if code, but the cleanest and most fool proof one.
Alternativ, you could use the Text as Key for a QHash, or normal hash, and go that way -> most likely the least amount of work.
-
-
hi @JonB
even so I personally don't do it, most of the time, option 3 is the way to go :)
Not the fastest, least amount if code, but the cleanest and most fool proof one.
Alternativ, you could use the Text as Key for a QHash, or normal hash, and go that way -> most likely the least amount of work.
@J.Hilk
Thanks for your prompt :)Alternativ, you could use the Text as Key for a QHash, or normal hash, and go that way -> most likely the least amount of work.
At least theoretically, I can't do that just in case a given text is duplicated with different values. Yes I know that's "dodgy", but it's not "right" to do it by look-up....
So you'd rather create an explicit model than a special member variable or data role.... I suppose
QListWidget
actually just creates a model for you and attaches aQListView
behind the scenes? -
@J.Hilk
Thanks for your prompt :)Alternativ, you could use the Text as Key for a QHash, or normal hash, and go that way -> most likely the least amount of work.
At least theoretically, I can't do that just in case a given text is duplicated with different values. Yes I know that's "dodgy", but it's not "right" to do it by look-up....
So you'd rather create an explicit model than a special member variable or data role.... I suppose
QListWidget
actually just creates a model for you and attaches aQListView
behind the scenes?@JonB said in Nicest way to have QListWidgetItem with extra data?:
So you'd rather create an explicit model than a special member variable or data role.... I suppose
QListWidget
actually just creates a model for you and attaches aQListView
behind the scenes?I'm unsure, models and Views were always and still are an area I've the least experience in.
That said, looking into the QListWidgetItem constructor, there's actually an constructor overload that accepts an int as 3rd parameter
QListWidgetItem::QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
and you can access it via type(), maybe you don't need to do anything extra?
-
@JonB said in Nicest way to have QListWidgetItem with extra data?:
So you'd rather create an explicit model than a special member variable or data role.... I suppose
QListWidget
actually just creates a model for you and attaches aQListView
behind the scenes?I'm unsure, models and Views were always and still are an area I've the least experience in.
That said, looking into the QListWidgetItem constructor, there's actually an constructor overload that accepts an int as 3rd parameter
QListWidgetItem::QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
and you can access it via type(), maybe you don't need to do anything extra?
QListWidgetItem::QListWidgetItem(const QIcon &icon, const QString &text, QListWidget *parent = nullptr, int type = Type)
No, I looked at that already, you can't store arbitrary data against each item via the
int type = Type
. That is used to indicate only the type of the item (custom item types, if you have need for that), it can only store values greater thanQListWidgetItem::UserType
. -
No need to subclass anything or do anything fancy. The functionality is already implemented
// QListWidgetItem* item item->setData(Qt::DisplayRole,QStringLiteral("Some Item")); item->setData(Qt::UserRole,3);
now you can use
item->data(Qt::UserRole).toInt()
to retrieve it.As you
QComboBox
, it uses this method internally -
No need to subclass anything or do anything fancy. The functionality is already implemented
// QListWidgetItem* item item->setData(Qt::DisplayRole,QStringLiteral("Some Item")); item->setData(Qt::UserRole,3);
now you can use
item->data(Qt::UserRole).toInt()
to retrieve it.As you
QComboBox
, it uses this method internally@VRonin
Yeah, that was indeed one of my proposed methods above, #2. As you say, I came to the conclusion that it didn't require sub-classing. Very interesting to hear that's the approachQComboBox
is taking, gives me a warm, wet feeling :)Can I just ask you if you have a comment on the alternative approach #1 above, whereby I would sub-class
QListWidgetItem
to add avalue
member? Makes it so neat to access from code. It's the way my beloved ASP.NET does itsListItem
s --- they havetext
& (optional)value
members --- whether these are in a combobox, list or whatever, and kind of feels "clean". What do you think of adding explicit member fields to derived-QListWidgetItem
s compared to going down thedata()
route? (BTW, I will probably use whichever solution generically to cover other places I will want this functionality, not just the particular case I have now, if that makes any difference.) -
@VRonin
Yeah, that was indeed one of my proposed methods above, #2. As you say, I came to the conclusion that it didn't require sub-classing. Very interesting to hear that's the approachQComboBox
is taking, gives me a warm, wet feeling :)Can I just ask you if you have a comment on the alternative approach #1 above, whereby I would sub-class
QListWidgetItem
to add avalue
member? Makes it so neat to access from code. It's the way my beloved ASP.NET does itsListItem
s --- they havetext
& (optional)value
members --- whether these are in a combobox, list or whatever, and kind of feels "clean". What do you think of adding explicit member fields to derived-QListWidgetItem
s compared to going down thedata()
route? (BTW, I will probably use whichever solution generically to cover other places I will want this functionality, not just the particular case I have now, if that makes any difference.)@JonB said in Nicest way to have QListWidgetItem with extra data?:
What do you think of adding explicit member fields
🤮
How a class stores its data is an implementation detail and should not be exposed to the outside.
I'd be 100% on board with subclassing and adding something likepublic: int type() const { return data(Qt::UserRole).toInt(); } void setType(int val) { setData(Qt::UserRole,val);}
But as a C++ programmer everytime I see a:
public: int type;
I shoot a bunny. So up to you if you want the soul of an innocent rabbit to haunt you forever for your sins
-
@JonB said in Nicest way to have QListWidgetItem with extra data?:
What do you think of adding explicit member fields
🤮
How a class stores its data is an implementation detail and should not be exposed to the outside.
I'd be 100% on board with subclassing and adding something likepublic: int type() const { return data(Qt::UserRole).toInt(); } void setType(int val) { setData(Qt::UserRole,val);}
But as a C++ programmer everytime I see a:
public: int type;
I shoot a bunny. So up to you if you want the soul of an innocent rabbit to haunt you forever for your sins
@VRonin
Well.... I'm a C/C#/JS/Python/Prolog programmer. C++ gives me headaches :) Of course I can wrap thatpublic
variable in a set/getter function (give me C# for this as a property any time...). So we'll be exposingint type() const
&void setType(int val)
from a sub-class in either approach.Now without that as an issue, I'm still really interested to hear whether you, as the implementer, want to store the value in a member variable or in the
data()
"table"/"property"/whatever you wish to call it?P.S.
Absolutely no bunnies were harmed in composing this email. -
@VRonin
Well.... I'm a C/C#/JS/Python/Prolog programmer. C++ gives me headaches :) Of course I can wrap thatpublic
variable in a set/getter function (give me C# for this as a property any time...). So we'll be exposingint type() const
&void setType(int val)
from a sub-class in either approach.Now without that as an issue, I'm still really interested to hear whether you, as the implementer, want to store the value in a member variable or in the
data()
"table"/"property"/whatever you wish to call it?P.S.
Absolutely no bunnies were harmed in composing this email.@JonB said in Nicest way to have QListWidgetItem with extra data?:
whether you, as the implementer, want to store the value in a member variable or in the data()
I would use
data
but only because that way you can pass that value to whatever other tool that uses theQAbstarctItemModel
API. But this is really down to the programmer, if you prefer a personalised private integer you are welcome to use it -
@JonB said in Nicest way to have QListWidgetItem with extra data?:
whether you, as the implementer, want to store the value in a member variable or in the data()
I would use
data
but only because that way you can pass that value to whatever other tool that uses theQAbstarctItemModel
API. But this is really down to the programmer, if you prefer a personalised private integer you are welcome to use it