PDA

View Full Version : TableView ProxyModel problem



poporacer
16th August 2011, 04:19
I have a tableview controlled by a proxy. In the tableview, the highest and lowest values are highlighted through the data function in the proxy. I want the user to be able to delete a selected row (just from the view, not the source!) I have one method almost figured out. The problem is that when a row is deleted, the correct data is not highlighted. I think I need to use mapToSource and mapFromSource, but I haven't been able to get it to work properly.
This is the method I use...when the user deletes a row, the row is hidden in the tableView, then when the tableview is iterated to find the highest and lowest numbers, the hidden row is skipped. Then the identified rows are sent to the proxy to highlight the correct cells.

Is this the correct way or is there a better way? How do I get this to work?

Here is the code for the tableView creation:
testclass.cpp

void TestClass::createTimerTable() // this is called in the constructor of the form
{
testModel= new QSqlRelationalTableModel(this);
testModel->setEditStrategy(QSqlTableModel::OnRowChange);
testModel->setTable("testtable");
testModel->setRelation(2,QSqlRelation("student","id", "LName"));
testModel->setRelation(3,QSqlRelation("testNum", "id","Test"));
testModel->setHeaderData(1,Qt::Horizontal,"Section");

proxy = new MyProxyModel (this);
proxy->setSourceModel(testModel);
ui->tableView->setModel(proxy);

connect(this,SIGNAL(sendRows(int, int, int, int)),
proxy, SLOT(getRows(int, int, int, int)));

//set up tableview
ui->tableView->setItemDelegate(new QSqlRelationalDelegate(this));
ui->tableView->setSelectionMode(QAbstractItemView::SingleSelectio n);
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows );
ui->tableView->setColumnHidden(0,true); // id
ui->tableView->resizeColumnsToContents();
ui->tableView->horizontalHeader()->setStretchLastSection(true);
}

void TestClass::updateTimeStats()
{
float totScore=0;
float totReactTime=0;
float lowScore=FLT_MAX;
int rowLowScore=0;
int rowHighScore =0;
int rowSlowReact =0;
int rowFastReact =0;
float slowReactTime =FLT_MIN;
float highScore=FLT_MIN;
float fastReactTime=FLT_MAX;
float currentScore=0;
float currentReactTime =0;
QString string;
int totRows=proxy->rowCount();
if (totRows >0)
{
for (int r=0; r<totRows; r++)
{
if (ui->printView->isRowHidden(r)) //Test if user deleted row
continue;
//QModelIndex sourceIndex=mapToSource(proxy->index(r,2));
//QModelIndex sourceIndex2=mapToSource(proxy->index(r,3));
//the above 2 lines gives a "mapToSource not declared" error
// #include <QModelIndex> is declared
currentScore=proxy->index(r,2).data(Qt::DisplayRole).toFloat();
currentReactTime=proxy->index(r,3).data(Qt::DisplayRole).toFloat();

if (currentScore < lowScore)
{
lowScore=currentScore;
rowLowScore=r;
}

if (currentScore > highScore)
{
highScore=currentScore;
rowHighScore =r;
}

if (currentReactTime > slowReactTime)
{
slowReactTime=currentReactTime;
rowSlowReact =r;
}

if (currentReactTime<fastReactTime)
{
fastReactTime=currentReactTime;
rowFastReact =r;
}

totTime+=currentTime;
totReactTime+=currentReactTime;

}
startModel->select();
}

myproxymodel.cpp

#include "myproxymodel.h"

MyProxyModel::MyProxyModel (QObject *parent) :
QSortFilterProxyModel(parent)
{

}
MyProxyModel::~MyProxyModel()
{

}

QVariant MyProxyModel::data ( const QModelIndex & index, int role ) const
{
QModelIndex sourceIndex = mapToSource(index);

if (!sourceIndex.isValid())
return QVariant();
if (m_slowReactRow<0)
{
if ( sourceIndex.row() == m_highScore && sourceIndex.column()== 2 && role == Qt::BackgroundRole )
{
return QVariant( Qt::yellow );
}
else if ( sourceIndex.row() == m_lowScore && sourceIndex.column()== 2 && role == Qt::BackgroundRole )
{
return QVariant( Qt::red );
}

else
{
return QSortFilterProxyModel::data( index, role );
}

}
else
{
if ( sourceIndex.row() == m_highScore && sourceIndex.column()== 2 && role == Qt::BackgroundRole )
{
return QVariant( Qt::yellow );
}
else if ( sourceIndex.row() == m_lowScore && sourceIndex.column()== 2 && role == Qt::BackgroundRole )
{
return QVariant( Qt::red );
}
else if (sourceIndex.row()== m_fastReactRow && sourceIndex.column()==3 && role == Qt::BackgroundRole)
{
return QVariant( Qt::yellow );
}
else if ( sourceIndex.row() == m_slowReactRow && sourceIndex.column()== 3 && role == Qt::BackgroundRole )
{
return QVariant( Qt::red );
}
else
{
return QSortFilterProxyModel::data( index, role );
}
}
}
void MyProxyModel::getRows( int rowLow,int rowHigh, int rowSlowReact, int rowFastReact)
{
m_highScore=rowHigh;
m_lowScore=rowLow;
m_slowReactRow= rowSlowReact;
m_fastReactRow= rowFastReact;
}

norobro
16th August 2011, 23:41
I don't understand. Do you have two views? One view where the user hides a row and another that shows the highlighted cells. If so you need to hide the row in the view that displays the proxy also.

Maybe something like this in your slot where you hide the row would work:
QModelIndexList list = view->selectionModel()->selectedRows();
foreach(QModelIndex index, list){
view1->hideRow(index.row()); // view that displays the orgininal data
view2->hideRow(proxy->mapFromSource(queryModel->index(index.row(),0)).row()); // view displaying proxy model
}
highlightCells();

Or is the user hiding rows in the view showing the proxy?

poporacer
17th August 2011, 00:59
There is only one view. The highest and lowest value in a column is highlighted in the view. I want the user to be able to remove a row from the view (without removing it from the source) The problem isn't in hiding the row, it is in highlighting the correct row AFTER a row is hidden.
I forgot to show the code for hiding the row;

void DlgPrintPreview::on_btnDeleteRow_clicked()
{
QModelIndex index = ui->printView->currentIndex();
if (!index.isValid())
return;
ui->printView->setRowHidden(index.row(),true);
highlightCells();

}

norobro
17th August 2011, 01:31
What confused me was this in updateTimeStats():
if (ui->printView->isRowHidden(r)) //Test if user deleted rowWhile in createTimerTable() you have:
ui->tableView->setModel(proxy);

Edit: Attached is a simple app based on one of your earlier (April, I think) posts that demonstrates that what you are trying to do should work.

poporacer
17th August 2011, 04:06
The code you posted did not work properly :( If you hide the rows in different orders you get varied results from nothing being highlighted to one item not being highlighted until you click on the table. I think this is close. I have to go to work. I will look closer at your code to see if I can figure out why it isn't working quite right...at least when it is highlighting, it is highlighting the correct number!

norobro
17th August 2011, 04:25
On my Linux box the only problem that I experienced was sometimes the highlight didn't show up until the mouse was over the view. Works well otherwise.

See if this fixes things. Add this statement to the MainWindow constructor:
ui->tableView->setSelectionBehavior(QAbstractItemView::SelectRows );and add an update at the end of the slot:
void MainWindow::pbClicked(){
QModelIndexList list = ui->tableView->selectionModel()->selectedRows();
foreach(QModelIndex index, list){
ui->tableView->hideRow(index.row());
}
highlightCells();
ui->tableView->update();
}

Edit: Oops. I see what you mean. It doesn't work if the view is sorted by a different column

norobro
17th August 2011, 13:55
I think adding the following statement to the MainWindow ctor and making highlightCells() a slot makes it work properly. The row numbers change on a sort (duh) and need to be rehighlighted.
connect(ui->tableView->horizontalHeader(),SIGNAL(sectionClicked(int)),thi s,SLOT(highlightCells()));

poporacer
17th August 2011, 13:59
Thanks....I will try it when I get back home this afternoon!

poporacer
18th August 2011, 13:54
It is still not always highlighting the cells after rows are hidden. I tried a couple different things for ui->tableview but I am not sure why sometimes it doesn't work. I will look at it some more tonight.

norobro
19th August 2011, 01:16
Maybe this will solve it:
void MainWindow::pbClicked(){
QModelIndexList list = ui->tableView->selectionModel()->selectedRows();
foreach(QModelIndex index, list){
ui->tableView->hideRow(index.row());
}
highlightCells();
// ui->tableView->update();
ui->tableView->setFocus(); // add this
}

poporacer
19th August 2011, 05:27
That looks like it works!!! I didn't think about setting the focus....Not sure why it needed that but it works. Now to get it to work in my code!

Thanks a million!

poporacer
23rd August 2011, 04:08
Works great! I had to modify it a bit for my application, but you got me in the right direction!!! Many thanks!!!