[SOLVED] Use of QIdentityProxyModel and QTableView (Qt5.2)
-
Hi all,
I'd like to use QIdentityProxyModel to add a special line in my tableview in order to avoid adding a button for inserting new data (i use the proxy for not adding fake data in my database for graphic purpose...).
I have as a sourcemodel, a QSqlTableModel.
With the following code, i have a line yes, but the text is blank. It seems that the data() function is not called for index.row=0! (that is where i want the special line). The data corresponding to the sourcemodel is well displayed.
Would you have an explanation what is wrong in my code ? Many thanks!@class ProxyModelForTablePers : public QIdentityProxyModel {
public :
ProxyModelForTablePers(QObject* parent = 0);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
};ProxyModelForTablePers::ProxyModelForTablePers (QObject* parent)
: QIdentityProxyModel (parent) {
}int ProxyModelForTablePers::rowCount(const QModelIndex &parent) const {
return (this->sourceModel()->rowCount()+1);//for adding a fake line
}
QVariant ProxyModelForTablePers::data(const QModelIndex &proxyIndex, int role) const {
if (!proxyIndex.isValid()) return QVariant (); if (proxyIndex.row() == 0) { return QVariant ("NEW"); } else return QIdentityProxyModel::data(proxyIndex, role);
}
bool ProxyModelForTablePers::setData(const QModelIndex &index, const QVariant &value, int role) {
if (index.row() == 0) { return true;//not yet imlemented will do the insert } else return QIdentityProxyModel::setData (index, value, role);
}
Qt::ItemFlags ProxyModelForTablePers::flags(const QModelIndex &index) const {
Qt::ItemFlags flags = QIdentityProxyModel::flags(index); flags |= Qt::ItemIsEditable; return flags;
}
QModelIndex ProxyModelForTablePers::index(int row, int column, const QModelIndex &parent) const {
if (row == 0) { return QModelIndex(parent); } else return this->sourceModel()->index(row-1, column, parent);
}
and the code called for the QTableview :
_SourceModel = new QSqlTableModel (this); FillSourceModelViewPers(); ProxyModelForTablePers * lProxy = new ProxyModelForTablePers (this); lProxy->setSourceModel(_SourceModel); this->setModel(lProxy); ("this" is a subclass of QTableView)
@
-
Anyone has an experience of this proxy ? Thanks.
[quote author="bizut" date="1390287425"]Hi all,
I'd like to use QIdentityProxyModel to add a special line in my tableview in order to avoid adding a button for inserting new data (i use the proxy for not adding fake data in my database for graphic purpose...).
I have as a sourcemodel, a QSqlTableModel.
With the following code, i have a line yes, but the text is blank. It seems that the data() function is not called for index.row=0! (that is where i want the special line). The data corresponding to the sourcemodel is well displayed.
Would you have an explanation what is wrong in my code ? Many thanks!@class ProxyModelForTablePers : public QIdentityProxyModel {
public :
ProxyModelForTablePers(QObject* parent = 0);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
};ProxyModelForTablePers::ProxyModelForTablePers (QObject* parent)
: QIdentityProxyModel (parent) {
}int ProxyModelForTablePers::rowCount(const QModelIndex &parent) const {
return (this->sourceModel()->rowCount()+1);//for adding a fake line
}
QVariant ProxyModelForTablePers::data(const QModelIndex &proxyIndex, int role) const {
if (!proxyIndex.isValid()) return QVariant (); if (proxyIndex.row() == 0) { return QVariant ("NEW"); } else return QIdentityProxyModel::data(proxyIndex, role);
}
bool ProxyModelForTablePers::setData(const QModelIndex &index, const QVariant &value, int role) {
if (index.row() == 0) { return true;//not yet imlemented will do the insert } else return QIdentityProxyModel::setData (index, value, role);
}
Qt::ItemFlags ProxyModelForTablePers::flags(const QModelIndex &index) const {
Qt::ItemFlags flags = QIdentityProxyModel::flags(index); flags |= Qt::ItemIsEditable; return flags;
}
QModelIndex ProxyModelForTablePers::index(int row, int column, const QModelIndex &parent) const {
if (row == 0) { return QModelIndex(parent); } else return this->sourceModel()->index(row-1, column, parent);
}
and the code called for the QTableview :
_SourceModel = new QSqlTableModel (this); FillSourceModelViewPers(); ProxyModelForTablePers * lProxy = new ProxyModelForTablePers (this); lProxy->setSourceModel(_SourceModel); this->setModel(lProxy); ("this" is a subclass of QTableView)
@
[/quote][quote author="bizut" date="1390287425"]Hi all,
I'd like to use QIdentityProxyModel to add a special line in my tableview in order to avoid adding a button for inserting new data (i use the proxy for not adding fake data in my database for graphic purpose...).
I have as a sourcemodel, a QSqlTableModel.
With the following code, i have a line yes, but the text is blank. It seems that the data() function is not called for index.row=0! (that is where i want the special line). The data corresponding to the sourcemodel is well displayed.
Would you have an explanation what is wrong in my code ? Many thanks!@class ProxyModelForTablePers : public QIdentityProxyModel {
public :
ProxyModelForTablePers(QObject* parent = 0);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &proxyIndex, int role = Qt::DisplayRole) const;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const;
};ProxyModelForTablePers::ProxyModelForTablePers (QObject* parent)
: QIdentityProxyModel (parent) {
}int ProxyModelForTablePers::rowCount(const QModelIndex &parent) const {
return (this->sourceModel()->rowCount()+1);//for adding a fake line
}
QVariant ProxyModelForTablePers::data(const QModelIndex &proxyIndex, int role) const {
if (!proxyIndex.isValid()) return QVariant (); if (proxyIndex.row() == 0) { return QVariant ("NEW"); } else return QIdentityProxyModel::data(proxyIndex, role);
}
bool ProxyModelForTablePers::setData(const QModelIndex &index, const QVariant &value, int role) {
if (index.row() == 0) { return true;//not yet imlemented will do the insert } else return QIdentityProxyModel::setData (index, value, role);
}
Qt::ItemFlags ProxyModelForTablePers::flags(const QModelIndex &index) const {
Qt::ItemFlags flags = QIdentityProxyModel::flags(index); flags |= Qt::ItemIsEditable; return flags;
}
QModelIndex ProxyModelForTablePers::index(int row, int column, const QModelIndex &parent) const {
if (row == 0) { return QModelIndex(parent); } else return this->sourceModel()->index(row-1, column, parent);
}
and the code called for the QTableview :
_SourceModel = new QSqlTableModel (this); FillSourceModelViewPers(); ProxyModelForTablePers * lProxy = new ProxyModelForTablePers (this); lProxy->setSourceModel(_SourceModel); this->setModel(lProxy); ("this" is a subclass of QTableView)
@
[/quote] -
Hi,
IIRC, the QIdentityProxyModel is not suited to do that. It can be used to modify the data but not to modify the model structure. You should rather start with a QSortFilterProxyModel
Hope it helps
-
IIRC you would have to also modify mapToSource
-
Hi,
Ok Thank you. Below is the code.
It works. I mean i have the "new line" displayed as the first line and the sql data displayed the other lines.
But i still have 2 problems :- The first is that when i move the mouse over the first line, the program crashes.
- Instead of having the text "NEW" in the cell where it should be displayed, i have a small rectangular and the text "N...".
Would you have some suggestions to make it work ? Thank you.
By the way, would you have some working example ? It would be great.
Many thanks!@
QModelIndex ProxyModelForTablePers::index(int row, int column, const QModelIndex &parent) const {if (row == 0) { return this->createIndex(row, column); } else return this->sourceModel()->index(row-1, column, parent);
}
QModelIndex ProxyModelForTablePers::mapFromSource(const QModelIndex & source) const
{
if (!sourceModel())
return QModelIndex();if (!source.parent().isValid()) return QModelIndex(); return index(source.row()+1, source.column());
}
QModelIndex ProxyModelForTablePers::mapToSource(const QModelIndex & proxy) const
{if (!sourceModel()) return QModelIndex(); if (proxy.row()==0) return QModelIndex(); return this->sourceModel()->index(proxy.row()-1, proxy.column());
}
@ -
Did you implement the data function ? If so, how does it look like ?
-
Hi,
Below is the my code :
@
ProxyModelForTablePers::ProxyModelForTablePers (QObject* parent)
: QSortFilterProxyModel (parent) {}
int ProxyModelForTablePers::rowCount(const QModelIndex &parent) const {
return (this->sourceModel()->rowCount()+1);
}QVariant ProxyModelForTablePers::data(const QModelIndex &proxyIndex, int role) const {
if (!proxyIndex.isValid()) return QVariant (); if (proxyIndex.row() == 0) { if (proxyIndex.column()==1) return QVariant ("new"); else return QVariant("test"); } else return QSortFilterProxyModel::data(proxyIndex, role); //return this->sourceModel()->data(this->mapToSource(proxyIndex), role);
}
bool ProxyModelForTablePers::setData(const QModelIndex &index, const QVariant &value, int role) {
if (index.row() == 0) { return false; } else return this->sourceModel()->setData (index, value, role);
}
Qt::ItemFlags ProxyModelForTablePers::flags(const QModelIndex &index) const {
Qt::ItemFlags flags = QSortFilterProxyModel::flags(index); flags |= Qt::ItemIsEditable; return flags;
}
QModelIndex ProxyModelForTablePers::index(int row, int column, const QModelIndex &parent) const {
if (row == 0) { return this->createIndex(row, column); } else return this->sourceModel()->index(row-1, column, parent);
}
QModelIndex ProxyModelForTablePers::mapFromSource(const QModelIndex & source) const
{
if (!sourceModel())
return QModelIndex();if (!source.parent().isValid()) return QModelIndex(); return index(source.row()+1, source.column());
}
QModelIndex ProxyModelForTablePers::mapToSource(const QModelIndex & proxy) const
{if (!sourceModel()) return QModelIndex(); if (proxy.row()==0) return QModelIndex(); return this->sourceModel()->index(proxy.row()-1, proxy.column());
}
TableViewPers::TableViewPers (QWidget *parent)
: QTableView (parent)
{this->setEditTriggers(QAbstractItemView::AllEditTriggers); this->setSortingEnabled(true); this->setSelectionBehavior(QAbstractItemView::SelectRows); this->setSelectionMode(QAbstractItemView::ContiguousSelection); _SourceModel = new QSqlTableModel (this, DataBaseManager::getManager()->getDataBase());
FillSourceModelViewPers();
ProxyModelForTablePers * lProxy = new ProxyModelForTablePers (this); lProxy->setSourceModel(_SourceModel); this->setModel(lProxy); this->setColumnHidden(0, true); this->resizeColumnsToContents();
}
@
-
You don't check what role you are given so basically you are giving "test" and "new" for every role whether it asks for DisplayRole or DecorationRole etc...
-
Hi, thanks for your help !
You are perfectly right! It is well displayed now !But i still have the crash problem when the mouse is over the first line. ..Like a onmouseOver event ? Have you got any clue about it ?
@
QVariant ProxyModelForTablePers::data(const QModelIndex &proxyIndex, int role) const {qDebug()<<proxyIndex.row()<<" "<<proxyIndex.column()<<" "<<rowCount(); if (role != Qt::DisplayRole) return QVariant(); if (!proxyIndex.isValid()) return QVariant (); if (proxyIndex.row() == 0) { if (proxyIndex.column()==1) return QVariant ("new"); else return QVariant("test"); } else //return QSortFilterProxyModel::data(proxyIndex, role); return this->sourceModel()->data(this->mapToSource(proxyIndex), role);
}
@ -
You should run your program using the debugger, from your proxy code here the only thing that could happen is that you don't have a source model which shouldn't happen since you are setting it in the constructor of TableViewPers
-
Hi,
I don't understand. Maybe that is a Qt bug ?
In debug mode, this are the last calls before crash :
QSortFilterProxyModel::parent
QTableView::visualRect
QAbstractItenView::viewportEventI removed the wrong line from mapFromSource
if (!source.parent().isValid())
return QModelIndex();But i still have the problem. Any idea ? Thanks
-
First thing to do is correct the data function to return proper values (or default) for each role
-
Of course ! I forgot about that oneā¦ Sorry