0

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 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 only when index.row() is equal to zero! I don't understand why!

#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);
                }
            }
        }
}
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
warcomeb
  • 13
  • 5
  • I've run into a similiar problem once, but I'm not 100% sure if this is the case here. In the QML file try replacing the `text: model.tabledata` in the delegate to `text: tabledata`. You can compare it to [my problem](https://stackoverflow.com/questions/66242814/i-get-undefined-data-from-qsqlquerymodel-in-my-listview-qml-sqlite-database). – sweak Mar 10 '21 at 15:33
  • 1
    please provide a [mre] – eyllanesc Mar 10 '21 at 15:45
  • @sweak I tried but nothing change! – warcomeb Mar 10 '21 at 16:35
  • @eyllanesc I'll do ASAP. Thanks – warcomeb Mar 10 '21 at 16:38
  • 1
    wait so `model.tabledata` gets printed out in `Component.onCompleted` inside the `delegate` but `Text` does not show up? If so, try to temporarily remove all formatting (sizes, anchors, colors, etc - replace with fixed sizes in every visual element). Try to make sure none of your geometry gets collapsed into zero-size, If you have GammaRay inspect your visual tree for mistakes. For example, `Layout.fillWidth: true` in `payeePage` won't work because `Rectangle` is not a layout, and then your `TableView` tries to `anchors.fill: parent` which is probably zero-sized. – Jack White Mar 10 '21 at 18:11
  • Correction: root `Rectangle` is not inside any layout that itself is inside this Component (that is - inside the QML file). If you insert an instance of this component into a layout, it won't fill its width since layout's attached property can't attach to something that does not exist in this context. And anyway height is not set so is zero by default (unless you specify it in external code), which is then forced onto `TableView` by anchors – Jack White Mar 10 '21 at 18:26

0 Answers0