Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

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:

    1. Override my items' flags() to return ItemIsEditable ORed in. (Not sure I can do this because Qt::ItemFlags QListWidgetItem::flags() const doesn't look virtual, but I get really confused here because Python/PyQt makes/shows all methods as overridable....).

    2. 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 my JEditableListWidget class that I want any items it creates to be my JEditableListWidgetItem instead of QListWidgetItem? 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 a JEditableListWidgetItem *

    @JonB said in Making QListWidget items editable "nicely":

    Override my items' constructor to go setFlags(flags() | ItemIsEditable).

    I'd use this solution



  • An alternative is to separate the model and view. Using a QStandardItemModel with a QTreeView implements the behaviour you want by default and it's basically the same thing as having QTreeWidget



  • @VRonin

    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 public QListWidgetItem 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 each QListWidgetItem. That means I need my own class JEditableListWidgetItem(QtWidgets.QListWidgetItem), right? 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? If I can't, I can't use a constructor-override, can I?? That's why I've had to use QListWidget::rowsInserted() as the only way?


  • Qt Champions 2017

    @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 what QListWidget does).
    • Create your own addItem overloads, as many as you want.


  • @kshegunov , @VRonin
    In that case, thanks very much genuinely/politely, but I have no intention of overriding QListView::addItem() and any other methods it might have for adding items, and maintaining that as QListView adds more methods in future versions.... (Nor redoing "aggregations" which QListWidget 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.


  • Qt Champions 2017

    @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.


  • Qt Champions 2017

    @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 several addItem() 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 :-;


  • Qt Champions 2017

    @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. :)


Log in to reply