Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. QML and Qt Quick
  4. TableView does't update, but list into model is full
QtWS25 Last Chance

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

Scheduled Pinned Locked Moved Unsolved QML and Qt Quick
tableviewqmlempty table
5 Posts 2 Posters 722 Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • W Offline
    W Offline
    warcomeb
    wrote on 9 Mar 2021, 08:57 last edited by
    #1

    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);
                    }
                }
            }
    }
    
    fcarneyF 1 Reply Last reply 10 Mar 2021, 15:13
    0
    • W Offline
      W Offline
      warcomeb
      wrote on 10 Mar 2021, 08:08 last edited by
      #2

      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

      1 Reply Last reply
      0
      • W warcomeb
        9 Mar 2021, 08:57

        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);
                        }
                    }
                }
        }
        
        fcarneyF Offline
        fcarneyF Offline
        fcarney
        wrote on 10 Mar 2021, 15:13 last edited by
        #3

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

        C++ is a perfectly valid school of magic.

        W 1 Reply Last reply 10 Mar 2021, 21:44
        0
        • fcarneyF fcarney
          10 Mar 2021, 15:13

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

          W Offline
          W Offline
          warcomeb
          wrote on 10 Mar 2021, 21:44 last edited by
          #4

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

          1 Reply Last reply
          0
          • fcarneyF Offline
            fcarneyF Offline
            fcarney
            wrote on 11 Mar 2021, 16:04 last edited by
            #5

            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.

            C++ is a perfectly valid school of magic.

            1 Reply Last reply
            0

            1/5

            9 Mar 2021, 08:57

            • Login

            • Login or register to search.
            1 out of 5
            • First post
              1/5
              Last post
            0
            • Categories
            • Recent
            • Tags
            • Popular
            • Users
            • Groups
            • Search
            • Get Qt Extensions
            • Unsolved