Add virtual rows & columns to a proxy model
Hi,
i have a QSortFilterProxyModel and i'd like to add some rows and columns, but only in the proxy model.
For example, i have 6 rows and 4 columns and i want to add an additional column with data not from the source model.
I've already reimplemented rowCount, columnCount and data. The QTableView shows the correct count of rows and columns but there is not data in the "virtual" column. I found out, that the QModelIndex rage in data() is only from column 0 to 3, but never comes to column 4.
What else do i have to do, to get the additional column(s)?
Thank you.
Regards,
Mani
Re: Add virtual rows & columns to a proxy model
So columnCount() of the proxy returns 5 but the proxy's data() never gets called with index.column==4?
Cheers,
_
Re: Add virtual rows & columns to a proxy model
Yes, this is the problem! The whole problem in one sentence ... :eek:
Re: Add virtual rows & columns to a proxy model
Ok, this is strange, the view should be trying to get data for those cells.
Can you post the code of your proxy model or maybe even a minimal example demonstrating the problem?
Cheers,
_
Re: Add virtual rows & columns to a proxy model
This demo model shows the problem. It starts with 6 rows and 4 columns and in the proxy model i remove 3 rows and add one column. The last column is created but there is no data in it, it's also not clickable.
Code:
#ifndef TestTableModel_H
#define TestTableModel_H
#include <QAbstractTableModel>
{
private:
typedef QVector<QVariant> RowData;
typedef QVector<RowData> ModelData;
public:
TestTableModel
(QObject *parent
= 0);
QVariant headerData
(int section, Qt
::Orientation orientation,
int role
) const;
private:
void init();
private:
ModelData mModelData;
};
#endif // TestTableModel_H
Code:
#include "TestTableModel.h"
{
init();
}
int TestTableModel
::rowCount(const QModelIndex &parent
) const {
if(parent.isValid())
return 0;
else
return mModelData.size();
}
int TestTableModel
::columnCount(const QModelIndex &parent
) const {
if(parent.isValid())
return 0;
else
{
if(mModelData.size() > 0)
return mModelData.at(0).size();
}
return 0;
}
{
if(role == Qt::DisplayRole)
{
if(index.isValid())
{
return mModelData.at(index.row()).at(index.column());
}
}
}
QVariant TestTableModel
::headerData(int section, Qt
::Orientation orientation,
int role
) const {
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
switch(section)
{
case 0:
return "Value1";
case 1:
return "Value2";
case 2:
return "Value3";
case 3:
return "Value4";
default:
}
}
}
void TestTableModel::init()
{
RowData rdA;
rdA.append("A");
rdA.append(1000);
rdA.append(800);
rdA.append(100);
mModelData.append(rdA);
RowData rdB;
rdB.append("B");
rdB.append(2500);
rdB.append(2000);
rdB.append(300);
mModelData.append(rdB);
RowData rdC;
rdC.append("C");
rdC.append(1400);
rdC.append(1120);
rdC.append(100);
mModelData.append(rdC);
RowData rdA1;
rdA1.append("A");
rdA1.append(1200);
rdA1.append(960);
rdA1.append(180);
mModelData.append(rdA1);
RowData rdA2;
rdA2.append("A");
rdA2.append(1000);
rdA2.append(800);
rdA2.append(100);
mModelData.append(rdA2);
RowData rdB1;
rdB1.append("B");
rdB1.append(1500);
rdB1.append(1200);
rdB1.append(100);
mModelData.append(rdB1);
}
And the proxy model
Code:
#ifndef TestTableProxyModel_H
#define TestTableProxyModel_H
#include <QSortFilterProxyModel>
{
private:
typedef QVector<QVariant> RowData;
typedef QVector<RowData> ModelData;
public:
TestTableProxyModel
(QObject *parent
= 0);
QVariant headerData
(int section, Qt
::Orientation orientation,
int role
) const;
void refreshView();
private:
int mRowCount;
int mColumnCount;
ModelData mTmpModelData;
bool mUpdateDone;
};
#endif // TestTableProxyModel_H
Code:
#include "TestTableProxyModel.h"
TestTableProxyModel
::TestTableProxyModel(QObject *parent
){
}
int TestTableProxyModel
::rowCount(const QModelIndex &parent
) const {
if(parent.isValid())
return 0;
if(mRowCount > 0 && mUpdateDone)
return mRowCount;
else
}
int TestTableProxyModel
::columnCount(const QModelIndex &parent
) const {
if(parent.isValid())
return 0;
if(mColumnCount > 0 && mUpdateDone)
return mColumnCount;
else
}
QVariant TestTableProxyModel
::headerData(int section, Qt
::Orientation orientation,
int role
) const {
if(mUpdateDone)
{
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
{
if(!mHeaderFields.isEmpty())
{
if(section < mHeaderFields.size())
return mHeaderFields.at(section);
else
}
}
}
}
{
if(mUpdateDone)
{
if(role == Qt::DisplayRole)
{
if(!mTmpModelData.isEmpty())
{
if(index.row() < mTmpModelData.size())
{
if(index.column() < mTmpModelData.at(index.row()).size())
return mTmpModelData.at(index.row()).at(index.column());
}
else
}
}
}
}
void TestTableProxyModel::refreshView()
{
mUpdateDone = false;
mRowCount = 3;
mColumnCount = 5;
for(int i=0;i<mColumnCount;i++)
for(int i=0;i<mRowCount;i++)
{
RowData rd;
for(int j=0;j<mColumnCount;j++)
mTmpModelData.append(rd);
}
mUpdateDone = true;
invalidate();
}
Re: Add virtual rows & columns to a proxy model
So where is this magical "refreshView()" method being called?
Your base model isn't calling any of the methods it should be when changing the model - things like beginInsertRows(), endInsertRows(), or even modelReset(). These things are necessary for the model to properly notify listeners (views, proxies, etc.) that something has changed and they need to update themselves. You shouldn't need to implement magic methods to get your proxy updated or to have to transfer data from your base model into the proxy.
In order to get clickable behaviour for your virtual column, you will need to implement the flags() method for your proxy.
Re: Add virtual rows & columns to a proxy model
Thank you for your reply.
The model itself should not be changed, i only want to add a "virtual" column with the proxy model to the view. refreshView() is called from a button on a form next to the table view. I also don't want to transfer any data from the base model to the proxy.
I have also reimplemented the flags() method but it does not change anything, same behaviour as before.
Re: Add virtual rows & columns to a proxy model
I found the solution here.
I had to add the following methods to my proxy class:
Code:
return createIndex(row,column,row);
}
//Works only for non-tree models
}
return index(source.row(), source.column(), source.parent());
}
return (sourceModel()&&proxy.isValid())
? sourceModel()->index(proxy.row(), proxy.column(), proxy.parent())
}
Re: Add virtual rows & columns to a proxy model
And here I thought elephants never forget. I guess that doesn't apply to old elephants.
Just got bit by this exact same issue this week, and finally decided to ask Google. That led me here, and adding the index() and parent() methods fixed it. (I had already added the map...() methods).
In my case, my proxy added a column which was mapped to one of the source model columns, but it split one of the source columns into two, each of which modified the original data - that is, if the original columns were x and y, it mapped x into x' and y', and y into z' by applying two different arithmetic transformations to the original x.