PDA

View Full Version : QSortFilterProxyModel crash with mapToSource()



Armin
3rd February 2010, 21:22
Hello,
I have the following problem: I use 2 tables where the second table has acolumn containing an index to the first (relation to id of entries in forst table). When I select an entry in the first table, the corresponding entry in the second one should be filtered. This works fine without QSortFilterProxyModel. If I use a QSortFilterProxyModel then I have to remap the selected index from the tableview to the datamodel using the QSortFilterProxyModel 's mapToSource(), but this call crashes for some reason. Searching for solution fails, so I hope I get one here.

In the source I just used native QSortFilterProxyModel , in my application I reimplemented it using a custom sort, I think this is not important, error is the same, so I tried to create a small compilable example with data etc, because the Signal "currentRowChanged" is fired immediately after start so the example crashes immediately (used debugger to find out that mapToSource() is the reason).

Hope I could make clear the problem, thanks in advance for any hints to solve that problem
Armin

Here is the code:

mainwindow.cpp with the "problem" in line 60


#include <QtGui>
#include <QtSql>
#include "mainwindow.h"
MainWindow::MainWindow()
{
createOtherDock();
createColorDock();
}
//---------------------------------------------------------------------------
void MainWindow::createOtherDock()
{
QDockWidget *dock = new QDockWidget(tr("Other"), this);

otherModel = new QSqlRelationalTableModel(this);
otherModel->setTable("other");
otherModel->select();

otherView = new QTableView(dock);
otherView->setModel(otherModel);

QSortFilterProxyModel *MyProxyModel = new QSortFilterProxyModel(this);
MyProxyModel->setSourceModel(otherModel);
MyProxyModel->sort(1, Qt::DescendingOrder);
otherView->setModel(MyProxyModel);

connect(otherView->selectionModel(),
SIGNAL(currentRowChanged(const QModelIndex &,
const QModelIndex &)),
this, SLOT(RowClicked(const QModelIndex &,
const QModelIndex &)));

dock->setWidget(otherView);
addDockWidget(Qt::RightDockWidgetArea, dock);
}
//---------------------------------------------------------------------------
void MainWindow::createColorDock()
{
QDockWidget *dock = new QDockWidget(tr("Color"), this);

colorModel = new QSqlRelationalTableModel(this);
colorModel->setTable("color");
colorModel->setRelation(color_Other, QSqlRelation("other", "id", "name"));
colorModel->select();

colorView = new QTableView(dock);
colorView->setModel(colorModel);

dock->setWidget(colorView);
addDockWidget(Qt::RightDockWidgetArea, dock);
}
//---------------------------------------------------------------------------
void MainWindow::RowClicked(const QModelIndex & newIndex, const QModelIndex & oldIndex)
{
QModelIndex proxyIndex;
int id;

if (newIndex.isValid())
{
// --->>>> the next line crashes <<<--- //
proxyIndex = MyProxyModel->mapToSource(newIndex);
if (proxyIndex.isValid())
{
QSqlRecord record = otherModel->record(proxyIndex.row());
id = record.value("id").toInt();
filterColorView(id);
}
}
}
//---------------------------------------------------------------------------
void MainWindow::filterColorView(int id)
{
colorModel->setFilter(QString("color.otherid = %1").arg(id));
colorModel->select();
colorView->horizontalHeader()->setVisible(colorModel->rowCount() > 0);
}



Header for mainwindow.spp


#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QtGui>
#include <QtSql>

enum {
other_Id = 0,
other_Name = 1,
};
enum {
color_Id = 0,
color_Name = 1,
color_Other = 2,
};

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow();
void filterColorView(int id);

private slots:
void RowClicked(const QModelIndex &, const QModelIndex &);
private:
void createOtherDock();
void createColorDock();

QSqlRelationalTableModel *otherModel;
QSqlRelationalTableModel *colorModel;

QTableView *otherView;
QTableView *colorView;

QSortFilterProxyModel *MyProxyModel;
};

#endif




main.cpp including data creation:


#include <QApplication>
#include <QtGui>
#include <QtSql>

#include "mainwindow.h"
//---------------------------------------------------------------------------
bool Connect()
{
QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("data.dat");
if (!db.open())
{
QMessageBox::warning(0, QObject::tr("Error"), db.lastError().text());
return (false);
}
return (true);
}
//---------------------------------------------------------------------------
void createDataBase()
{
QSqlQuery query;
query.exec("DROP TABLE other");
query.exec("DROP TABLE color");

query.exec("CREATE TABLE other ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name VARCHAR(10) NOT NULL)");

query.exec("CREATE TABLE color ("
"id INTEGER PRIMARY KEY AUTOINCREMENT, "
"name VARCHAR(40) NOT NULL, "
"otherid INTEGER NOT NULL, "
"FOREIGN KEY (otherid) REFERENCES other)");

query.prepare("INSERT INTO other (id, name) "
"VALUES (:id, :name)");
query.bindValue(":id", 1);
query.bindValue(":name", "A");
query.exec();
query.bindValue(":id", 2);
query.bindValue(":name", "b");
query.exec();
query.bindValue(":id", 3);
query.bindValue(":name", "C");
query.exec();

query.prepare("INSERT INTO color (id, name, otherid) "
"VALUES (:id, :name, :otherid)");
query.bindValue(":id", 1);
query.bindValue(":name", "Red");
query.bindValue(":otherid", 1);
query.exec();
query.bindValue(":id", 2);
query.bindValue(":name", "Green");
query.bindValue(":otherid", 2);
query.exec();
query.bindValue(":id", 3);
query.bindValue(":name", "Blue");
query.bindValue(":otherid", 3);
query.exec();
}
//---------------------------------------------------------------------------

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

bool existingData = QFile::exists("data.dat");
if (!Connect())
{
return(1);
}
if (!existingData)
{
createDataBase();
}
MainWindow Window;
Window.show();
// Window.filterColorView();
return app.exec();
}



project file for Qt Creator:


QT += sql
SOURCES += main.cpp \
mainwindow.cpp
HEADERS += mainwindow.h

norobro
6th February 2010, 04:11
I think you need to change line 21 in mainwindow.cpp to:
MyProxyModel = new QSortFilterProxyModel(this);
You've already declared *MyProxyModel in your header file.
HTH

Armin
6th February 2010, 16:17
Thanks a lot norobro, this was really a stupid mistake from myself.
Have a nice day
Armin

norobro
6th February 2010, 20:07
Armin,
You're welcome. The same thing happens to me. Sometimes, looking at my own code, I see what I expect to see not what is actually there.
Norm