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
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