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

QTableView doesn't update and has strange cell style by default



  • Hi,

    Why do the cells have these two squares on the right? This is a QTableView created with the Design tab.

    weird table

    Moreover, When I click de "Add product" button I call the update function on the model but the table doesn't display the value, what I'm missing?
    The model of the table uses the m_activeProduct as underlying data.

    Button logic

    connect(ui->addProductButton, &QPushButton::clicked, this, [this](){
            Product p;
            p.m_name = "New product";
            p.m_price = 0.0;
            m_activeReceipt->addProduct(p);
            auto model = static_cast<ProductModel*>(ui->productsTableView->model());
            model->update();
        });
    

    Model update

    void ProductModel::update(){
        qDebug() << rowCount() << columnCount();
        auto top_left = index(0,0,QModelIndex());
        auto bottom_right = index(rowCount(),columnCount(),QModelIndex());
        emit dataChanged(top_left, bottom_right, {Qt::EditRole});
    }
    

  • Lifetime Qt Champion

    Please show us your model. I don't see how changing m_activeReceipt should somehow magically update the model.



  • Here is the .h

    #ifndef PRODUCTMODEL_H
    #define PRODUCTMODEL_H
    
    #include <QAbstractTableModel>
    #include "receipt.h"
    class ProductModel : public QAbstractTableModel
    {
    public:
        ProductModel(Receipt * data, QObject* parent = nullptr);
        int rowCount(const QModelIndex &parent = QModelIndex()) const;
        int columnCount(const QModelIndex &parent = QModelIndex()) const;
        QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
        QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
        bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
        Qt::ItemFlags flags(const QModelIndex &index) const;
        void update( ) ;
    private:
        Receipt * m_data;
    };
    
    #endif // PRODUCTMODEL_H
    

    And the .cpp

    #include "productmodel.h"
    #include <QDebug>
    
    ProductModel::ProductModel(Receipt *data, QObject *parent):
        QAbstractTableModel(parent),
        m_data(data)
    {
    
    }
    
    int ProductModel::rowCount(const QModelIndex &parent) const
    {
        return m_data->products().size();
    }
    
    int ProductModel::columnCount(const QModelIndex &parent) const
    {
        return 2;
    }
    
    QVariant ProductModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
        if (role != Qt::DisplayRole)
            return QVariant();
    
        if (orientation == Qt::Horizontal) {
            if (section % 2 == 0)
                return "Product";
            else
                return "Price";
        } else {
            return QString("%1").arg(section + 1);
        }
    }
    
    QVariant ProductModel::data(const QModelIndex &index, int role) const
    {
        if (role == Qt::DisplayRole) {
            auto p = m_data->products();
            if(index.column() == 0)
                return p[index.row()].m_name;
            else if(index.column() == 1){
                return p[index.row()].m_price;
            }
        }
        else if (role == Qt::EditRole ) {
            auto p = m_data->products();
            if(index.column() == 0)
                return p[index.row()].m_name;
            else if(index.column() == 1){
                return p[index.row()].m_price;
            }
        }else{
            return QColor(Qt::white);
        }
        return QVariant();
    }
    
    bool ProductModel::setData(const QModelIndex &index, const QVariant &value, int role)
    {
        bool ok;
        if (index.isValid() && role == Qt::EditRole) {
            if(index.column() == 0){
                auto p = m_data->products();
                p[index.row()].m_name = value.toString();
                emit dataChanged(index, index);
                return true;
            }
            else if( float val = value.toFloat(&ok); index.column() == 1 && ok){
                auto p = m_data->products();
                p[index.row()].m_price =val;
                emit dataChanged(index, index);
                return true;
            }
        }
        return false;
    }
    
    Qt::ItemFlags ProductModel::flags(const QModelIndex &index) const
    {
        return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;
    }
    
    void ProductModel::update(){
        auto top_left = index(rowCount()-1,columnCount()-1,QModelIndex());
        auto bottom_right = index(rowCount()-1,columnCount()-1,QModelIndex());
        emit dataChanged(top_left, bottom_right, {Qt::EditRole});
    }
    

  • Lifetime Qt Champion

    So my question stands - how do you put your new data into the model?
    Also you should not return QColor(Qt::white); for every role you don't process.

    /edit: looks like you hold the data outside the model - don't do this.



  • @pachedo said in QTableView doesn't update and has strange cell style by default:

        auto bottom_right = index(rowCount(),columnCount(),QModelIndex());
        emit dataChanged(top_left, bottom_right, {Qt::EditRole});
    

    In addition to @Christian-Ehrlicher .

    This may not matter/be relevant to the behaviour you show, but I have two observations here:

    • I think it ought be bottom_right = index(rowCount() - 1, columnCount() - 1, QModelIndex());

    • If addProduct() adds a row to your model(?), dataChanged is not the right signal to emit. You should be using begin/endInsertRows().

    Your

        }else{
            return QColor(Qt::white);
        }
    

    probably means you are returning QColor(Qt::white); when this is called asking about whether the item has a checkbox, and maybe that is causing your checkbox(es) to be shown?


Log in to reply