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

Should I access an element of a ListView outside of a delegate and How?



  • I have a QML / C++ question. How to use and edit an element of QAbstractListModel outside of a view delegate ?

    I created a toy example of what I try to do. I have the feeling that I'm missing some understanding on MVC in QML.

    On the c++ side I have a "Contact" class derived from QObject storing all my contact data, a list of those contacts (ContactList), and aQAbstractListModel(ContactListModel) based on this list.

    On the QML side I want 2 separate Components. On the left a QListView displaying a list of contacts, only some part of the contact class are used here (e.g name). On the right side I have an another Component that display the current Contact (the one selected in the listview) this component should also allow to edit the content of the Contact, eg name/description etc.. and update the list view accordingly.

    C++:
    Contact:

    class Contact : public QObject{
        Q_OBJECT
        Q_PROPERTY(QString description READ description WRITE setDescription NOTIFY descriptionChanged)
    
    public:
        explicit Contact(QObject* parent=nullptr,
                         QString i_name =QString(),
                         QString i_desc =QString(),
                         bool i_checked = false);
    
    
        QString description() const;
        void setDescription(QString desc);
    
        QString name;
        bool checked;
    signals:
        void descriptionChanged();
    private:
        QString m_description;
    
    };
    

    ContactList:

    class ContactList : public QObject
    {
        Q_OBJECT
        Q_PROPERTY(int currentIndex READ currentIndex WRITE setCurrentIndex )
        Q_PROPERTY(Contact* currentItem READ currentContact WRITE setCurrentContact )
    
    public:
        explicit ContactList(QObject *parent = nullptr);
    
        QVector<Contact*> contacts() const;
    
        bool setItemAt(int index, Contact* item);
    
        int currentIndex() const;
        void setCurrentIndex(int index);
    
        Contact* currentContact() const;
        void setCurrentContact(Contact* contact);
    
    signals:
        void preItemAppended();
        void postItemAppended();
    
        void preItemRemoved(int index);
        void postItemRemoved();
    
    public slots:
        void appendItem();
        void removeItem(int index);
    
    private:
        QVector<Contact*> m_contacts;
        int m_currentIndex;
        Contact* m_currentContact;
    };
    

    ContactListModel:

    class ContactListModel : public QAbstractListModel
    {
        Q_OBJECT
        Q_PROPERTY(ContactList* list READ list WRITE setList )
    
    public:
        explicit ContactListModel(QObject *parent = nullptr);
    
        enum {
            CheckRole = Qt::UserRole,
            NameRole,
            DescriptionRole
        };
    
        // Basic functionality:
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
    
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    
        // Editable:
        bool setData(const QModelIndex &index, const QVariant &value,
                     int role = Qt::EditRole) override;
    
        Qt::ItemFlags flags(const QModelIndex& index) const override;
    
        virtual QHash<int, QByteArray> roleNames() const override;
    
        ContactList* list() const;
        void setList(ContactList *list);
    
    private:
        ContactList *m_list;
    };
    

    On the QML side I have my listView

        Layout.fillWidth: true
        Layout.fillHeight: true
        id: contacts_list_view
        clip: true
        
        model: ContactModel {
            id: _contactmodel
            list: contactList
        }
        
        delegate:
            RowLayout {
            CheckBox {
                checked: model.checked
                onCheckStateChanged: {
                    console.log(" current Index before " + contacts_list_view.currentIndex)
                    contacts_list_view.currentIndex = index;
                    console.log(" current Index after " + contacts_list_view.currentIndex)
                    contactList.currentIndex = index
                }
            }
            TextField {
                text: model.name
            }
        }
    }
    

    and my other Component that should display and edit the data from a single Contact:

    
    ColumnLayout{
        id: contact_sheet
        Layout.fillWidth: true
        Layout.preferredWidth: 800
    
        TextInput{
            id: _contact_description
            Layout.fillWidth: true
            Layout.preferredHeight: 100
            text: "Contact Description "
        }
        TextField {
            text: contactList.currentContact.description
        }
    }
    

    I've tried several things but I don't understand how I should edit a single Contact and notify the two items when something changed (either current index, or contact info ).


Log in to reply