[Solved] qml: problem with TableView refresh on model update



  • Hello everyone!

    I have simple QML app with TableView on screen. This view displays data from my custom model - derived from QAbstractTableModel:

    @#include "pswlistmodel.h"
    #include <QDebug>

    PswListModel::PswListModel(QObject parent)
    : QAbstractTableModel(parent)
    , hidePsws(true)
    {
    //test
    for (int i=0; i<10; ++i)
    {
    PswElement
    e = new PswElement();
    e->login = "login " + QString::number(i);
    e->name = "name " + QString::number(i);
    e->password = "password " + QString::number(i);
    this->elements.append(e);
    }
    }

    PswListModel::~PswListModel()
    {
    qDeleteAll(this->elements);
    this->elements.clear();
    }

    int PswListModel::rowCount(const QModelIndex& /parent/) const
    {
    return this->elements.size();
    }

    int PswListModel::columnCount(const QModelIndex& /parent/) const
    {
    return 3;
    }

    QVariant PswListModel::data(const QModelIndex& index, int role) const
    {
    if (this->elements.isEmpty())
    return QVariant();

    if (index.row() >= this->elements.size())
        return QVariant();
    
    
    PswElement *e = this->elements[index.row()];
    
    if (role == Qt::DisplayRole)
    {
        //name
        if (index.column() == 0)
            return e->name;
    
        //login
        if (index.column() == 1)
            return e->login;
    
        //password
        if (index.column() == 2)
        {
            if (!this->hidePsws)
                return e->password;
            else
                return "***";
        }
    }
    else if (role == PswNameRole)
        return e->name;
    else if (role == PswLoginRole)
        return e->login;
    else if (role == PswPswRole)
    {
        qDebug() << "get psw (" << index.row() << "), hide: " << this->hidePsws;
        if (!this->hidePsws)
            return e->password;
        else
            return "***";
    }
    
    return QVariant();
    

    }

    QVariant PswListModel::headerData(int section, Qt::Orientation orientation, int role) const
    {
    if (orientation == Qt::Horizontal)
    {
    if (role == Qt::DisplayRole)
    {
    if (section == 0)
    return QString("Name");
    else if (section == 1)
    return QString("Login");
    else if (section == 2)
    return QString("Password");
    }
    else if (role == PswNameRole)
    return "Name";
    else if (role == PswLoginRole)
    return "Login";
    else if (role == PswPswRole)
    return "Password";
    }
    else
    if (orientation == Qt::Vertical)
    return QString();

    return QVariant::Invalid;
    

    }

    QHash<int, QByteArray> PswListModel::roleNames() const
    {
    QHash<int, QByteArray> roles;
    roles[PswNameRole] = "name";
    roles[PswLoginRole] = "login";
    roles[PswPswRole] = "password";
    return roles;
    }

    void PswListModel::showPasswords(bool value)
    {
    qDebug() << "showPasswords: " << value;
    this->hidePsws = value;

    QModelIndex idTop = QAbstractTableModel::index(0, 0);
    QModelIndex idBottom = QAbstractTableModel::index(this->elements.size(), 4);
    
    emit dataChanged(idTop, idBottom);
    

    }@

    TableView in qml works fine, it displays all data from model.

    Now there is CheckBox in qml screen for toggling passwords. When state changes I am calling PswListModel::showPasswords from my custom model (from qDebug, I can see that value is changing). This should toggle the passwords visibility from "***" to real passwords. However, even if emitting dataChanged signal, TableView view in qlm is not refreshed.

    I am using Qt is 5.4.0, QtQuick 2.4 and QtQuick.Controls 1.3. Platform: Windows 7.

    Thanks in advance.


  • Moderators

    Hi,
    @
    QModelIndex idTop = QAbstractTableModel::index(0, 0);
    QModelIndex idBottom = QAbstractTableModel::index(this->elements.size(), 4);
    @

    I think since idTop starts from 0, idBottom should be 1 less.



  • Good point. Unfortunately that didn't help. Even if the range is correct (from elements.size()-1 to 3), table view in qml is not updated. This approach seems to be wrong.

    I finally figured it out:

    @void PswListModel::showPasswords(bool value)
    {
    qDebug() << "showPasswords: " << value;
    this->showPsws = value;

    this->beginResetModel();
    this->endResetModel();
    

    } @

    Reseting model invokes update of table in qml.



  • you may could tell the view that your data changed instead of resetting the whole model. You can specify which data. Here for the whole table:

    @emit dataChanged(index(0,0), index(rowCount()-1,columnCount()-1));@



  • That was my original problem: emitting dataChanged signal didn't refreshed the TableView.



  • uhm. dataChanged works. There is something wrong elsewhere.
    index in dataChanged is wrong, not only elementsSize()-1 but also for the columns you are using 4 instead of 2. That could be a reason.

    Did you tried to see if data is invoked after the call to showPasswords.

    Also in showPassword you are updating this->showPsws while in data you are using this->hidePsws. Could be that data is called but you are returing always the same value.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.