Making QListWidget items editable "nicely"
-
I want to derive a class from
QListWidget
in which all items are automatically editable (regardless of how they might be added).I have followed all advice on the web to make each item editable. I did it via
QListWidget::rowsInserted()
, which I'm hoping is the only way items can be added(?). Here's my lovely Python/PyQt code:class JEditableListWidget(QtWidgets.QListWidget): def __init__(self, parent: QtWidgets.QWidget=None): super().__init__(parent) def rowsInserted(self, parent: QtCore.QModelIndex, start: int, end: int): super().rowsInserted(parent, start, end) for i in range(start, end + 1): lwi = self.item(i) lwi.setFlags(lwi.flags() | QtCore.Qt.ItemIsEditable)
All fine & dandy, for what I have tested.
However, I find this "procedural" way of having to change an item flag when being added a bit "ugly". Are either of the following possible/easy to implement as an alternative:
-
Override my items'
flags()
to returnItemIsEditable
ORed in. (Not sure I can do this becauseQt::ItemFlags QListWidgetItem::flags() const
doesn't lookvirtual
, but I get really confused here because Python/PyQt makes/shows all methods as overridable....). -
Override my items' constructor to go
setFlags(flags() | ItemIsEditable)
.
In both case I assume(?) I would need to derive a
class JEditableListWidgetItem(QtWidgets.QListWidgetItem)
. But is there a way to tell myJEditableListWidget
class that I want any items it creates to be myJEditableListWidgetItem
instead ofQListWidgetItem
? I don't see that.(In my C#/ASP.NET days, they had something like a
QListWidgetItem QListWidget::createItem()
method, you could change that to return your sub-derived class for items if you wanted to.)I'll accept an answer in C++ to translate to Python/PyQt, but if it requires C++ shenanigans such as "templates" as the only way to achieve I won't be able to use it.
-
-
@JonB said in Making QListWidget items editable "nicely":
But is there a way to tell my JEditableListWidget class that I want any items it creates to be my JEditableListWidgetItem instead of QListWidgetItem?
No, the creation is hidden inside the private
QListModel
but you can get around it by only only using http://doc.qt.io/qt-5/qlistwidget.html#addItem-1 and http://doc.qt.io/qt-5/qlistwidget.html#insertItem that allow you to pass aJEditableListWidgetItem *
@JonB said in Making QListWidget items editable "nicely":
Override my items' constructor to go setFlags(flags() | ItemIsEditable).
I'd use this solution
-
No, the creation is hidden inside the private QListModel
So, could you kindly extend Qt's
QListWidget
(and other widgets like this too) to supply a publicQListWidgetItem QListWidget::createItem()
, please, which would be so useful/powerful? ;-)you can get around it by only only using http://doc.qt.io/qt-5/qlistwidget.html#addItem-1 and http://doc.qt.io/qt-5/qlistwidget.html#insertItem that allow you to pass a JEditableListWidgetItem *
It's to be a generic control. So other programmers might use
addItem(const QString &label)
etc. Unless those in turn go via the two methods you mention (do they??), I can't use it (and, no, I don't want to hide/seal up/reimplement all the other possible methods, thank you).Override my items' constructor to go setFlags(flags() | ItemIsEditable).
I'd use this solution
Yep, thought so :) Thanks!
HANG ON. That's the constructor for eachQListWidgetItem
. That means I need my ownclass JEditableListWidgetItem(QtWidgets.QListWidgetItem)
, right? But you haven't told me how I can make myJEditableListWidget
so whenever it creates an item (e.g.QListWidget::addItem(const QString &label)
) I can make that be myJEditableListWidgetItem
? If I can't, I can't use a constructor-override, can I?? That's why I've had to useQListWidget::rowsInserted()
as the only way? -
@JonB said in Making QListWidget items editable "nicely":
But you haven't told me how I can make my JEditableListWidget so whenever it creates an item (e.g. QListWidget::addItem(const QString &label)) I can make that be my JEditableListWidgetItem?
You can't.
That's why I've had to use QListWidget::rowsInserted() as the only way?
Follow the suggested alternative:
- Derive your list widget from
QListView
. - Aggregate a
QStandardItemModel
instance in it (basically whatQListWidget
does). - Create your own
addItem
overloads, as many as you want.
- Derive your list widget from
-
@kshegunov , @VRonin
In that case, thanks very much genuinely/politely, but I have no intention of overridingQListView::addItem()
and any other methods it might have for adding items, and maintaining that asQListView
adds more methods in future versions.... (Nor redoing "aggregations" whichQListWidget
has already done for me.)I started out with
QListWidget::rowsInserted()
override working as shown. Has coped with whatever I have tested adding, unless you know somewhere where it won't work? I asked if it was easy to do it a less "ugly" way, and for my purposes I conclude it is not. Fair enough, I'll stick with my hack :) But I have learned useful stuff from you. -
@JonB said in Making QListWidget items editable "nicely":
I have no intention of overriding QListView::addItem() and any other methods it might have for adding items
You don't need to do any overriding, as
QListView
has none of the described, which is the whole point. The view knows of no items, only a model, hence what I wrote above - just have the model inside your derived class and add the the items to it through your class. -
To make it more explicit I'd use
class CustomListWidget : public QListView { Q_OBJECT Q_DISABLE_COPY(CustomListWidget) public: CustomListWidget(QWidget *parent = Q_NULLPTR) : QListView(parent), m_model(new QStandardItemModel(this)) { QListView::setModel(m_model); } private: QStandardItemModel* m_model; void setModel(QAbstractItemModel *) Q_DECL_OVERRIDE{} };
This should already work
[Fixed minor typos ~kshegunov]
-
@kshegunov
Sorry, I mis-phrased.just have the model inside your derived class and add the the items to it through your class.
My class will encapsulate the model, not derive from it, right? So I'll have to write my class's
addItem()
,deleteItem()
, etc. etc. "transfer" methods to call the corresponding on the model, right? No thanks! Sorry if you guys regard me as mad/obstructive, just don't want to have to do that :)I originally wrote 5 lines of code to override
QListWidget::rowsInserted()
. It's done now and works. It'll do me. Is there anything actually wrong with doing it that way? Thanks awfully. -
@JonB said in Making QListWidget items editable "nicely":
So I'll have to write my class's addItem(), deleteItem(), etc. etc. "transfer" methods to call the corresponding on the model, right?
Yes. A couple of one-liners.
Is there anything actually wrong with doing it that way?
If you're happy, I'm. You asked if there's a better way, that's the better way. If you want to stick with your solution, that's also perfectly fine with me.
-
@kshegunov said in Making QListWidget items editable "nicely":
Yes. A couple of one-liners.
But it isn't "a couple". It's a whole load of them! I expect my widget to offer at least all the methods
QListWidget
does. However, it's all very well being able to, say, write severaladdItem()
methods of your own with overloads matching the overloads provided by the model or whatever, you don't have to write overloaded functions in Python which doesn't have overloads in the sense that C++/C# does!! Which is why my life is a headache while yours is plain-sailing :-; -
@JonB said in Making QListWidget items editable "nicely":
Which is why my life is a headache while yours is plain-sailing
Yeah, you would think that, wouldn't you. :)