Sort and Filter a QSqlQueryModel: Difference between revisions

From Qt Wiki
Jump to navigation Jump to search
No edit summary
No edit summary
Line 1: Line 1:
[[Category:HowTo]]<br />[[Category:Developing with Qt]]<br />[toc align_right=&quot;yes&amp;quot; depth=&quot;2&amp;quot;]
[[Category:HowTo]]
[[Category:Developing with Qt]]
[toc align_right="yes" depth="2"]


= Sort and Filter a QSqlQueryModel =
= Sort and Filter a QSqlQueryModel =
Line 9: Line 11:
== Example usage ==
== Example usage ==


<code><br />QSortFilterSqlQueryModel '''model = new QSortFilterSqlQueryModel(this);<br />model-&gt;setQuery(&quot;SELECT u.id, u.name, c.name FROM users AS u LEFT JOIN cities AS c ON (u.city_id = c.id)&quot;);<br />model-&gt;setFilterColumn(&quot;u.name&amp;quot;); // will filter by user name<br />model-&gt;setFilterFlags(Qt::MatchStartsWith);<br />model-&gt;setFilter(&quot;Iv&amp;quot;);<br />model-&gt;select();
<code>
<br />/''' executes this query:<br />SELECT u.id, u.name, c.name FROM users AS u LEFT JOIN cities AS c ON (u.city_id = c.id)<br />WHERE u.name LIKE 'Iv%'<br />*/<br /></code>
QSortFilterSqlQueryModel '''model = new QSortFilterSqlQueryModel(this);
model->setQuery("SELECT u.id, u.name, c.name FROM users AS u LEFT JOIN cities AS c ON (u.city_id = c.id)");
model->setFilterColumn("u.name"); // will filter by user name
model->setFilterFlags(Qt::MatchStartsWith);
model->setFilter("Iv");
model->select();


You can connect a QLineEdit's textChanged signal to the filter slot:<br />filter is the same as setFilter, but it also call select();<br /><code><br />// dynamic filtering on user input<br />QLineEdit '''search = new QLineEdit(this);<br />connect(search, SIGNAL (textChanged(QString)), model, SLOT (filter(QString)));<br /></code>
/''' executes this query:
<br />Sorting is done automatically by the view, using the sort implementation. You can also use setSort to set a sort order before select()ing.
SELECT u.id, u.name, c.name FROM users AS u LEFT JOIN cities AS c ON (u.city_id = c.id)
<br />h2. Warnings
WHERE u.name LIKE 'Iv%'
<br />''' It has only been tested in Windows using MySQL<br />* It won't work using setQuery(QSqlQuery). I didn't needed it so you have to reimplement it yourself.<br />* Works for me. May not work for you. :P
*/
</code>
 
You can connect a QLineEdit's textChanged signal to the filter slot:
filter is the same as setFilter, but it also call select();
<code>
// dynamic filtering on user input
QLineEdit '''search = new QLineEdit(this);
connect(search, SIGNAL (textChanged(QString)), model, SLOT (filter(QString)));
</code>
 
Sorting is done automatically by the view, using the sort implementation. You can also use setSort to set a sort order before select()ing.
 
h2. Warnings
 
''' It has only been tested in Windows using MySQL
* It won't work using setQuery(QSqlQuery). I didn't needed it so you have to reimplement it yourself.
* Works for me. May not work for you. :P


== Code ==
== Code ==
Line 21: Line 45:
=== QSortFilterSqlQueryModel.h ===
=== QSortFilterSqlQueryModel.h ===


<code><br />#ifndef QSORTFILTERSQLQUERYMODEL_H<br />#define QSORTFILTERSQLQUERYMODEL_H
<code>
#ifndef QSORTFILTERSQLQUERYMODEL_H
#define QSORTFILTERSQLQUERYMODEL_H


#include &lt;QSqlQueryModel&amp;gt;<br />#include &lt;QSqlRecord&amp;gt;
#include <QSqlQueryModel>
#include <QSqlRecord>


class QSortFilterSqlQueryModel : public QSqlQueryModel<br />{<br /> Q_OBJECT
class QSortFilterSqlQueryModel : public QSqlQueryModel
{
Q_OBJECT


public:
public:
Line 31: Line 60:
explicit QSortFilterSqlQueryModel(QObject *parent = 0);
explicit QSortFilterSqlQueryModel(QObject *parent = 0);


//void setQuery(const QSqlQuery &amp;query);<br /> void setQuery(const QString &amp; query, const QSqlDatabase &amp; db = QSqlDatabase::database() );
//void setQuery(const QSqlQuery &amp;query);
void setQuery(const QString &amp; query, const QSqlDatabase &amp; db = QSqlDatabase::database() );


public slots:
public slots:


void setFilterColumn (const QString &amp; column);<br /> void setFilterFlags (const Qt::MatchFlag flags);<br /> void setFilter( const QString &amp; filter );<br /> void filter( const QString &amp; filter );
void setFilterColumn (const QString &amp; column);
void setFilterFlags (const Qt::MatchFlag flags);
void setFilter( const QString &amp; filter );
void filter( const QString &amp; filter );


void select();
void select();


virtual void setSort (int column, Qt::SortOrder order);<br /> virtual void sort (int column, Qt::SortOrder order);
virtual void setSort (int column, Qt::SortOrder order);
virtual void sort (int column, Qt::SortOrder order);


private:
private:


QSqlDatabase queryDB;<br /> QString queryClause;<br /> Qt::MatchFlag filterFlags;<br /> QString filterString;<br /> QString filterColumn;<br /> int sortKeyColumn;<br /> Qt::SortOrder sortOrder;
QSqlDatabase queryDB;
QString queryClause;
Qt::MatchFlag filterFlags;
QString filterString;
QString filterColumn;
int sortKeyColumn;
Qt::SortOrder sortOrder;


signals:
signals:
Line 49: Line 89:
};
};


#endif // QSORTFILTERSQLQUERYMODEL_H<br /></code>
#endif // QSORTFILTERSQLQUERYMODEL_H
</code>


=== QSortFilterSqlQueryModel.cpp ===
=== QSortFilterSqlQueryModel.cpp ===


<code><br />#include &quot;QSortFilterSqlQueryModel.h&amp;quot;<br />#include &lt;QtSql&amp;gt;<br />#include &lt;QString&amp;gt;
<code>
#include "QSortFilterSqlQueryModel.h"
#include <QtSql>
#include <QString>


QSortFilterSqlQueryModel::QSortFilterSqlQueryModel(QObject '''parent) :<br /> QSqlQueryModel(parent)<br />{
QSortFilterSqlQueryModel::QSortFilterSqlQueryModel(QObject '''parent) :
<br />}
QSqlQueryModel(parent)
<br />void QSortFilterSqlQueryModel::setQuery(const QString &amp;query, const QSqlDatabase &amp;db)<br />{<br /> queryClause = query;<br /> queryDB = db;
{
<br /> filterString.clear();<br /> //filterColumn.clear();<br /> filterFlags = Qt::MatchStartsWith;<br /> sortKeyColumn = –1;<br /> sortOrder = Qt::AscendingOrder;<br />}
<br />void QSortFilterSqlQueryModel::select()<br />{
<br /> if (queryClause.isEmpty() || (!queryDB.isValid()))<br /> return;
<br /> QString query = queryClause;
<br /> if (!filterString.isEmpty() &amp;&amp; !filterColumn.isEmpty()) {<br /> QString whereClause;<br /> QString esFilterString = filterString;<br /> QString esFilterColumn = filterColumn;
<br /> if (filterFlags &amp; Qt::MatchExactly) {<br /> whereClause = &quot;WHERE %1 = %2&amp;quot;;<br /> } else if (filterFlags &amp; Qt::MatchStartsWith) {<br /> whereClause = &quot;WHERE %1 LIKE %2&amp;quot;;<br /> esFilterString.append(&quot;'''&quot;);<br /> } else if (filterFlags &amp; Qt::MatchEndsWith) {<br /> whereClause = &quot;WHERE %1 LIKE %2&amp;quot;;<br /> esFilterString.prepend(&quot;*&quot;);<br /> } else if (filterFlags &amp; Qt::MatchRegExp) {<br /> whereClause = &quot;WHERE %1 REGEXP %2&amp;quot;;<br /> } else if (filterFlags &amp; Qt::MatchWildcard) {<br /> whereClause = &quot;WHERE %1 LIKE %2&amp;quot;;<br /> } else if (filterFlags &amp; Qt::MatchContains) {<br /> whereClause = &quot;WHERE %1 LIKE 2&amp;quot;;<br /> esFilterString.append(&quot;'''&quot;);<br /> esFilterString.prepend(&quot;'''&quot;);<br /> } else { return; } // unhandled filterflag
<br /> QSqlDriver '''driver = queryDB.driver();<br /> esFilterColumn = driver-&gt;escapeIdentifier(filterColumn, QSqlDriver::FieldName);<br /> QSqlField field; field.setType(QVariant::String); field.setValue(esFilterString);<br /> esFilterString = driver-&gt;formatValue(field);<br /> if (filterFlags &amp; Qt::MatchStartsWith || Qt::MatchEndsWith || Qt::MatchWildcard) {<br /> esFilterString = esFilterString.replace(&quot;&quot;, &quot;&quot;);<br /> //if (filterFlags &amp; Qt::MatchWildcard)<br /> esFilterString = esFilterString.replace(&quot;'''&quot;, &quot;&quot;);<br /> }


//whereClause.arg(esFilterColumn).arg(esFilterString); // don't know why it doesn't work<br /> whereClause = whereClause.replace(&quot;%1&amp;quot;, esFilterColumn).replace(&quot;%2&amp;quot;, esFilterString);<br /> query.append(&quot; &quot; + whereClause);<br /> }
}


if (sortKeyColumn &gt;= 0) {<br /> QString orderClause;<br /> orderClause = &quot;ORDER BY &quot; + QString::number(sortKeyColumn+1) + &quot; &quot; + ((sortOrder == Qt::AscendingOrder) ? &quot;ASC&amp;quot; : &quot;DESC&amp;quot;);<br /> query.append(&quot; &quot; + orderClause);<br /> }
void QSortFilterSqlQueryModel::setQuery(const QString &amp;query, const QSqlDatabase &amp;db)
{
queryClause = query;
queryDB = db;
 
filterString.clear();
//filterColumn.clear();
filterFlags = Qt::MatchStartsWith;
sortKeyColumn = –1;
sortOrder = Qt::AscendingOrder;
}
 
void QSortFilterSqlQueryModel::select()
{
 
if (queryClause.isEmpty() || (!queryDB.isValid()))
return;
 
QString query = queryClause;
 
if (!filterString.isEmpty() &amp;&amp; !filterColumn.isEmpty()) {
QString whereClause;
QString esFilterString = filterString;
QString esFilterColumn = filterColumn;
 
if (filterFlags &amp; Qt::MatchExactly) {
whereClause = "WHERE %1 = %2";
} else if (filterFlags &amp; Qt::MatchStartsWith) {
whereClause = "WHERE %1 LIKE %2";
esFilterString.append("'''");
} else if (filterFlags &amp; Qt::MatchEndsWith) {
whereClause = "WHERE %1 LIKE %2";
esFilterString.prepend("*");
} else if (filterFlags &amp; Qt::MatchRegExp) {
whereClause = "WHERE %1 REGEXP %2";
} else if (filterFlags &amp; Qt::MatchWildcard) {
whereClause = "WHERE %1 LIKE %2";
} else if (filterFlags &amp; Qt::MatchContains) {
whereClause = "WHERE %1 LIKE 2";
esFilterString.append("'''");
esFilterString.prepend("'''");
} else { return; } // unhandled filterflag
 
QSqlDriver '''driver = queryDB.driver();
esFilterColumn = driver->escapeIdentifier(filterColumn, QSqlDriver::FieldName);
QSqlField field; field.setType(QVariant::String); field.setValue(esFilterString);
esFilterString = driver->formatValue(field);
if (filterFlags &amp; Qt::MatchStartsWith || Qt::MatchEndsWith || Qt::MatchWildcard) {
esFilterString = esFilterString.replace("", "");
//if (filterFlags &amp; Qt::MatchWildcard)
esFilterString = esFilterString.replace("'''", "");
}
 
//whereClause.arg(esFilterColumn).arg(esFilterString); // don't know why it doesn't work
whereClause = whereClause.replace("%1", esFilterColumn).replace("%2", esFilterString);
query.append(" " + whereClause);
}
 
if (sortKeyColumn >= 0) {
QString orderClause;
orderClause = "ORDER BY " + QString::number(sortKeyColumn+1) + " " + ((sortOrder == Qt::AscendingOrder) ? "ASC" : "DESC");
query.append(" " + orderClause);
}


QSqlQueryModel::setQuery(query, queryDB);
QSqlQueryModel::setQuery(query, queryDB);
Line 74: Line 173:
}
}


void QSortFilterSqlQueryModel::setSort(int column, Qt::SortOrder order)<br />{<br /> sortKeyColumn = column;<br /> sortOrder = order;<br />}
void QSortFilterSqlQueryModel::setSort(int column, Qt::SortOrder order)
{
sortKeyColumn = column;
sortOrder = order;
}


void QSortFilterSqlQueryModel::sort(int column, Qt::SortOrder order)<br />{<br /> if ((sortKeyColumn != column) || (sortOrder != order)) {<br /> setSort(column, order);<br /> select();<br /> }<br />}
void QSortFilterSqlQueryModel::sort(int column, Qt::SortOrder order)
{
if ((sortKeyColumn != column) || (sortOrder != order)) {
setSort(column, order);
select();
}
}


void QSortFilterSqlQueryModel::setFilterColumn(const QString &amp;column)<br />{<br /> filterColumn = column;<br />}
void QSortFilterSqlQueryModel::setFilterColumn(const QString &amp;column)
{
filterColumn = column;
}


void QSortFilterSqlQueryModel::setFilter(const QString &amp;filter) {<br /> filterString = filter;<br />}
void QSortFilterSqlQueryModel::setFilter(const QString &amp;filter) {
filterString = filter;
}


void QSortFilterSqlQueryModel::setFilterFlags(const Qt::MatchFlag flags)<br />{<br /> filterFlags = flags;<br />}
void QSortFilterSqlQueryModel::setFilterFlags(const Qt::MatchFlag flags)
{
filterFlags = flags;
}


void QSortFilterSqlQueryModel::filter(const QString &amp;filter)<br />{<br /> if (filterString != filter) {<br /> setFilter(filter);<br /> select();<br /> }<br />}
void QSortFilterSqlQueryModel::filter(const QString &amp;filter)
{
if (filterString != filter) {
setFilter(filter);
select();
}
}

Revision as of 09:57, 25 February 2015

[toc align_right="yes" depth="2"]

Sort and Filter a QSqlQueryModel

QSortFilterSqlQueryModel is a QSqlQueryModel subclass that allows server-side sorting and filtering.

Feel free to download and test it.

Example usage

QSortFilterSqlQueryModel '''model = new QSortFilterSqlQueryModel(this);
model->setQuery("SELECT u.id, u.name, c.name FROM users AS u LEFT JOIN cities AS c ON (u.city_id = c.id)");
model->setFilterColumn("u.name"); // will filter by user name
model->setFilterFlags(Qt::MatchStartsWith);
model->setFilter("Iv");
model->select();

/''' executes this query:
SELECT u.id, u.name, c.name FROM users AS u LEFT JOIN cities AS c ON (u.city_id = c.id)
WHERE u.name LIKE 'Iv%'
*/

You can connect a QLineEdit's textChanged signal to the filter slot: filter is the same as setFilter, but it also call select();

// dynamic filtering on user input
QLineEdit '''search = new QLineEdit(this);
connect(search, SIGNAL (textChanged(QString)), model, SLOT (filter(QString)));

Sorting is done automatically by the view, using the sort implementation. You can also use setSort to set a sort order before select()ing.

h2. Warnings

It has only been tested in Windows using MySQL

  • It won't work using setQuery(QSqlQuery). I didn't needed it so you have to reimplement it yourself.
  • Works for me. May not work for you. :P

Code

QSortFilterSqlQueryModel.h

#ifndef QSORTFILTERSQLQUERYMODEL_H
#define QSORTFILTERSQLQUERYMODEL_H

#include <QSqlQueryModel>
#include <QSqlRecord>

class QSortFilterSqlQueryModel : public QSqlQueryModel
{
 Q_OBJECT

public:

explicit QSortFilterSqlQueryModel(QObject *parent = 0);

//void setQuery(const QSqlQuery &amp;query);
 void setQuery(const QString &amp; query, const QSqlDatabase &amp; db = QSqlDatabase::database() );

public slots:

void setFilterColumn (const QString &amp; column);
 void setFilterFlags (const Qt::MatchFlag flags);
 void setFilter( const QString &amp; filter );
 void filter( const QString &amp; filter );

void select();

virtual void setSort (int column, Qt::SortOrder order);
 virtual void sort (int column, Qt::SortOrder order);

private:

QSqlDatabase queryDB;
 QString queryClause;
 Qt::MatchFlag filterFlags;
 QString filterString;
 QString filterColumn;
 int sortKeyColumn;
 Qt::SortOrder sortOrder;

signals:

};

#endif // QSORTFILTERSQLQUERYMODEL_H

QSortFilterSqlQueryModel.cpp

  1. include "QSortFilterSqlQueryModel.h"
  2. include <QtSql>
  3. include <QString>

QSortFilterSqlQueryModel::QSortFilterSqlQueryModel(QObject parent) :

QSqlQueryModel(parent)

{

}

void QSortFilterSqlQueryModel::setQuery(const QString &query, const QSqlDatabase &db) {

queryClause = query;
queryDB = db;
filterString.clear();
//filterColumn.clear();
filterFlags = Qt::MatchStartsWith;
sortKeyColumn = –1;
sortOrder = Qt::AscendingOrder;

}

void QSortFilterSqlQueryModel::select() {

if (queryClause.isEmpty() || (!queryDB.isValid()))
return;
QString query = queryClause;
if (!filterString.isEmpty() && !filterColumn.isEmpty()) {
QString whereClause;
QString esFilterString = filterString;
QString esFilterColumn = filterColumn;
if (filterFlags & Qt::MatchExactly) {
whereClause = "WHERE %1 = %2";
} else if (filterFlags & Qt::MatchStartsWith) {
whereClause = "WHERE %1 LIKE %2";
esFilterString.append("");
} else if (filterFlags & Qt::MatchEndsWith) {
whereClause = "WHERE %1 LIKE %2";
esFilterString.prepend("*");
} else if (filterFlags & Qt::MatchRegExp) {
whereClause = "WHERE %1 REGEXP %2";
} else if (filterFlags & Qt::MatchWildcard) {
whereClause = "WHERE %1 LIKE %2";
} else if (filterFlags & Qt::MatchContains) {
whereClause = "WHERE %1 LIKE 2";
esFilterString.append("");
esFilterString.prepend("");
} else { return; } // unhandled filterflag
QSqlDriver driver = queryDB.driver();
esFilterColumn = driver->escapeIdentifier(filterColumn, QSqlDriver::FieldName);
QSqlField field; field.setType(QVariant::String); field.setValue(esFilterString);
esFilterString = driver->formatValue(field);
if (filterFlags & Qt::MatchStartsWith || Qt::MatchEndsWith || Qt::MatchWildcard) {
esFilterString = esFilterString.replace("", "");
//if (filterFlags & Qt::MatchWildcard)
esFilterString = esFilterString.replace("", "");
}

//whereClause.arg(esFilterColumn).arg(esFilterString); // don't know why it doesn't work

whereClause = whereClause.replace("%1", esFilterColumn).replace("%2", esFilterString);
query.append(" " + whereClause);
}

if (sortKeyColumn >= 0) {

QString orderClause;
orderClause = "ORDER BY " + QString::number(sortKeyColumn+1) + " " + ((sortOrder == Qt::AscendingOrder) ? "ASC" : "DESC");
query.append(" " + orderClause);
}

QSqlQueryModel::setQuery(query, queryDB);

}

void QSortFilterSqlQueryModel::setSort(int column, Qt::SortOrder order) {

sortKeyColumn = column;
sortOrder = order;

}

void QSortFilterSqlQueryModel::sort(int column, Qt::SortOrder order) {

if ((sortKeyColumn != column) || (sortOrder != order)) {
setSort(column, order);
select();
}

}

void QSortFilterSqlQueryModel::setFilterColumn(const QString &column) {

filterColumn = column;

}

void QSortFilterSqlQueryModel::setFilter(const QString &filter) {

filterString = filter;

}

void QSortFilterSqlQueryModel::setFilterFlags(const Qt::MatchFlag flags) {

filterFlags = flags;

}

void QSortFilterSqlQueryModel::filter(const QString &filter) {

if (filterString != filter) {
setFilter(filter);
select();
}

}