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

TableView does't update, but list into model is full



  • Hello,
    I am trying to update a table with data coming from an external process (into QML I lunch a CLI tool that returns a lot of strings and with that, I update the table). I am using TableView to show these data, and I wrote a Model class and a List class: the Model class extend QAbstractTableModel, indeed the list class extend QObject.
    I am sure that the list is full (I print the contents with qDebug()), but the table is always empty! Can you help me?
    I put the classes below!
    Thanks
    Marco

    #ifndef PAYEELIST_H
    #define PAYEELIST_H
    
    #include <QObject>
    #include <QList>
    #include "payee.h"
    
    class PayeeList : public QObject
    {
        Q_OBJECT
    public:
        explicit PayeeList(QObject *parent = nullptr);
    
        QList<Payee> items() const;
    
    //    bool setItemAt (int index, const Payee &item);
        void clear (void);
        void append (const Payee& item);
    
    signals:
        void preItemAppended ();
        void postItemAppended ();
    
        void preItemRemoved (int index);
        void postItemRemoved ();
    
    //public slots:
    //    void appendItem ();
    
    private:
        QList<Payee> mItems;
    };
    
    #endif // PAYEELIST_H
    
    #include "payeelist.h"
    
    PayeeList::PayeeList(QObject *parent) : QObject(parent)
    {
    
    }
    
    QList<Payee> PayeeList::items() const
    {
        return mItems;
    }
    
    void PayeeList::clear()
    {
        mItems.clear();
    }
    
    void PayeeList::append(const Payee &item)
    {
        emit preItemAppended();
        mItems.append(item);
        emit postItemAppended();
    }
    
    
    #ifndef PAYEEMODEL_H
    #define PAYEEMODEL_H
    
    #include <QAbstractTableModel>
    
    #include "payeelist.h"
    
    //class PayeeList;
    
    class PayeeModel : public QAbstractTableModel
    {
        Q_OBJECT
        Q_PROPERTY(PayeeList *list READ list WRITE setList)
    
    public:
        explicit PayeeModel(QObject *parent = nullptr);
    
        enum
        {
            HeadingRole = Qt::UserRole + 1,
            DataRole
        };
    
        enum
        {
            IdColumn = 0,
            NameColumn,
            TypeColumn
        };
    
        // Basic functionality:
        int rowCount(const QModelIndex &parent = QModelIndex()) const override;
        int columnCount(const QModelIndex &parent = QModelIndex()) const override;
    
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
    
        virtual QHash<int, QByteArray> roleNames() const override;
    
        PayeeList *list (void) const;
        void setList (PayeeList *list);
    
    private:
        PayeeList *mList;
    };
    
    #endif // PAYEEMODEL_H
    
    #include "payeemodel.h"
    
    PayeeModel::PayeeModel(QObject *parent)
        : QAbstractTableModel(parent),
          mList(nullptr)
    {
    }
    
    int PayeeModel::rowCount(const QModelIndex &parent) const
    {
        // For list models only the root node (an invalid parent) should return the list's size. For all
        // other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
        if (parent.isValid() || !mList)
            return 0;
    
        qDebug() << "LIST SIZE:" << mList->items().size();
        return mList->items().size() + 1;
    }
    
    int PayeeModel::columnCount(const QModelIndex &parent) const
    {
        if (parent.isValid() || !mList)
            return 0;
    
        return 3;
    }
    
    QVariant PayeeModel::data(const QModelIndex &index, int role) const
    {
        if (!index.isValid() || !mList)
            return QVariant();
    
        switch (role)
        {
        case DataRole:
        {
            qDebug() << "INDEX ROW:" << index.row();
            if (index.row() > 0)
            {
                const Payee item = mList->items().at(index.row() - 1);
    
                switch (index.column())
                {
                case IdColumn:
                    return QString::number(item.id());
                    break;
                case NameColumn:
                    return QString(item.name());
                    break;
                case TypeColumn:
                    return QString(item.type().name());
                    break;
                }
            }
            else
            {
                switch (index.column())
                {
                case IdColumn:
                    return QString("Id");
                    break;
                case NameColumn:
                    return QString("Name");
                    break;
                case TypeColumn:
                    return QString("Type");
                    break;
                }
            }
        }
            break;
    
        case HeadingRole:
            if (index.row() == 0)
            {
                return true;
            }
            else
            {
                return false;
            }
            break;
    
        default:
            break;
        }
        return QVariant();
    }
    
    QHash<int, QByteArray> PayeeModel::roleNames() const
    {
        QHash<int, QByteArray> names;
        names[HeadingRole] = "tableheading";
        names[DataRole] = "tabledata";
        return names;
    }
    
    PayeeList *PayeeModel::list (void) const
    {
        return mList;
    }
    
    void PayeeModel::setList (PayeeList *list)
    {
        beginResetModel();
    
        if (mList)
        {
            mList->disconnect(this);
        }
    
        mList = list;
    
        if (mList)
        {
            connect(mList, &PayeeList::preItemAppended, this, [=]()
            {
                const int index = mList->items().size();
                beginInsertRows(QModelIndex(), index, index);
            });
            connect(mList, &PayeeList::postItemAppended, this, [=]()
            {
                endInsertRows();
            });
        }
    
        endResetModel();
    }
    

    The QML file is:

    import QtQuick 2.12
    import QtQuick.Controls 2.0
    import QtQuick.Layouts 1.3
    
    import PlutoTool 1.0
    
    Rectangle {
        id: payeePage
        Layout.fillWidth: true
    
        property var title: "TITLE"
            TableView {
                columnSpacing: 1
                rowSpacing: 1
    
                anchors.fill: parent
                clip: false
    
                property var columnWidths: [50, (parent.width - 220), 150]
                columnWidthProvider: function (column) { return columnWidths[column] }
    
                model: PayeeModel {
                    list: lPayeeList
                }
    
                delegate: Rectangle {
                    implicitWidth: 200
                    implicitHeight: 30
                    border.color: "black"
                    border.width: 0
                    color: (tableheading == true) ? "#990033":"#EEEEEE"
                    Text {
                        text: model.tabledata
                        color: (tableheading == true) ? "#FFFFFF":"#000000"
                        font.bold: (tableheading == true) ? true : false
                        anchors.centerIn: parent
                    }
                    Component.onCompleted: {
                        console.log(model.tabledata);
                    }
                }
            }
    }
    


  • Hello,
    I added some debug prints and I can see that the rowCount function of the model is called a lot of time and return the correct length of the list, but the data function is called every time with index.row() equal to zero! I don't understand why!

    Any ideas?

    Marco



  • @warcomeb said in TableView does't update, but list into model is full:

    but the table is always empty!

    What does "empty" mean? No data? No delegates shown?

    model.tabledata

    Why are you prefixing tabledata with model. ?

    id: payeePage

    What is the height of this Rectangle?



  • @fcarney said in TableView does't update, but list into model is full:

    @warcomeb said in TableView does't update, but list into model is full:

    but the table is always empty!

    What does "empty" mean? No data? No delegates shown?

    No delegates shown

    model.tabledata

    Why are you prefixing tabledata with model. ?

    I tried both solutions: with and without model as a prefix.

    id: payeePage

    What is the height of this Rectangle?

    mmmm I don't set the height....



  • Make a role for Qt::DisplayRole and call it "display". Then return data by column like you are doing to support tables. If I remember correctly TableViews are stuck on using the display role. ListViews seem to be more flexible. I don't know why though. I had to use 2 methods to support both listviews and tableviews if I remember corrrectly.

    You should only have to use the word "display" to support this role in your delegates. You can add it as another case to your role case so you can support both types of views.