PDA

View Full Version : Multiples QSqlQueryModel and QTableView



Netheril
6th April 2010, 02:16
Hi, I'm making multiples queries to a database by just pressing a QPushButton and reading the query from a QLineEdit. I need to show that queries in a QTabWidget that has multiples QTableViews each one in a different tab. I created a QThread, an in the run() a send a signal with one dynamic model to the QDialog where I have the QTabWidget. Here's the code:



class GeneralSearchThread : public QThread
{
Q_OBJECT
public:
explicit GeneralSearchThread( QObject *parent = 0 );
~GeneralSearchThread();
void makeQuery( const QString &query );

signals:
void modelReadytoRead( QSqlQueryModel *model ); //this signal will be connected to the QDialog.

public slots:

protected:
void run();

private:
QString nameUser;
QString passUser;
QString queryString;

QList< QSqlQueryModel *> listaModels;
};

GeneralSearchThread::GeneralSearchThread( QObject *parent ) : QThread( parent )
{
}

GeneralSearchThread::~GeneralSearchThread()
{
wait();

qDeleteAll(listaModels); /// I get the problem here!!!
listaModels.clear(); /// I get the problem here!!!
}

void GeneralSearchThread::makeQuery( const QString &query )
{
queryString = query;
start();
}

void GeneralSearchThread::run()
{
QSqlDatabase db = QSqlDatabase::database( "someName" );
if( db.open() )
{
QSqlQueryModel *model = new QSqlQueryModel;
model->setQuery( queryString, db );
listaModels.append( model );
emit modelReadytoRead( model );
db.close();
}
}


The question here, is that I'm creating the QSqlQueryModels dynamically and trying to store them in a QList (which I call listaModels) and delete it in the destructor of the QThread. But I get a problem of Segmentation fault . But when I put away the lines inside the destructor I get no problems, but I'm afraid of a memory leak. Does anyone know how to solve this problem?, the QSqlQueryModels get deleted when the driver is closed and I'm re-deleting them?. Thanks a lot in advanced.
Extra Info: Driver: QMYSQL3, OS: Ubuntu 9.04, gcc version 4.4.1, Qt version 4.6.

borisbn
6th April 2010, 04:26
Look, your models got a "db" parameter in their constructors, but it's lifitime is only to run function finish. Maybe model's destructor want to read or write to QSqlDatabase ?

ajg85
6th April 2010, 19:01
I believe your problem may be caused by db.close(); on line 52. Your query model objects are pointers that are remaining in scope with a reference to this QSqlDatabase object after it has been closed.


void QSqlDatabase::close ()
Closes the database connection, freeing any resources acquired, and invalidating any existing QSqlQuery objects that are used with the database.

This will also affect copies of this QSqlDatabase object.

See also removeDatabase().

Perhaps using a persistent database connection which remains in scope until after you delete your query models will work better. You can close your database connection in the deconstructor after deleting the queries. Unless you need connections to multiple different databases from the same thread this would also be more efficient as you won't need to constantly open and close connections as well.

Netheril
7th April 2010, 18:38
Hi borisbn and ajg85 thanks a lot for the answers, they help me to find out the right answer. All I had to do was just like ajg85 said: using a persistent database connection which remains in scope. Also I've found a better way to delete the models QSqlQueryModel and the QTableViews. The QTableViews are deleted when I delete the QTabWidget because the QTabWidget gets the QTableViews as childs by using the inserTab function. For the QSqlQueryModels, I used a QList of QSharedPointers and I don't have to worry for delete them. I include the code for those who had the same problem:

The .h:


class GeneralSearchThread : public QThread
{
Q_OBJECT
public:
explicit GeneralSearchThread( QObject *parent = 0 );
~GeneralSearchThread();
void makeQuery( const QString &query );

signals:
void modelReadytoRead( QSqlQueryModel *model );

protected:
void run();

private:
QString queryString;
QList< QSharedPointer<QSqlQueryModel> > sqlQueryModelList; // God bless templates.
};


The .cpp:


GeneralSearchThread::GeneralSearchThread( QObject *parent ) : QThread( parent )
{
}

GeneralSearchThread::~GeneralSearchThread()
{
wait();
}

void GeneralSearchThread::makeQuery( const QString &query )
{
queryString = query;
start();
}

void GeneralSearchThread::run()
{
QSqlDatabase db = QSqlDatabase::database( "someName" );
if( db.open() )
{
QSharedPointer<QSqlQueryModel> model = QSharedPointer<QSqlQueryModel>( new QSqlQueryModel );
sqlQueryModelList.append( model );
model.data()->setQuery( queryString, db );
emit modelReadytoRead( model.data() );
db.close();
}
}


To two things. First: there wasn't any problem by calling the db.close() method at the end of the run() method of the QThread.
Second: In my QDialog, in the .h I created a QSqlDatabase db; variable, and in the .cpp in the destructor, I call the db.close() method. I did not call any removeDatabase().

That's all, thanks a lot guys for the answers, Now I run my program and I don't get any nasty message in the console, I just get the beautiful exited with code 0.