[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.
-
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));@
-
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.