PDA

View Full Version : QTableView sorting



gabriels
1st February 2006, 19:49
Hi,

I use Qt v4.0.1 (OpenSource) on the Win XP.
My app query some rows from the mysql server and show it into the QTableView.
What I want is to sort the QTableView when the header column is clicked.
I tried to use this slot but it didn't work :

void QTableView::sortByColumn ( int column ) [slot]
( Sorts the model by the values in the given column.)

Can anybody help me or give me some suggestions, please?
Thanks,
Gabriel S

These are parts of my code :
.............

QTableView *tableView = new QTableView(WindMaincall);
QSqlQueryModel *model = new QSqlQueryModel(tableView);

connect(tableView->horizontalHeader(),SIGNAL(sectionClicked(int)), tableView, SLOT(sortByColumn(int)));
...................
model->setQuery( "SELECT field1,field2 FROM table1" );
tableView->setModel(model);

KjellKod
1st February 2006, 21:39
What do you mean that it didn't work? Can you provide some more info?

--- I haven't tried that function on QTableView, but I've tried it's 'cousin' function on QTableWidget
void QTableWidget::sortItems ( int column, Qt::SortOrder order = Qt::AscendingOrder )
Sorts all the rows in the table widget based on column and order.

And that worked w/out any problems (similar to your code)

Everall
2nd February 2006, 10:15
have you used
setClickable(true) on your QHeaderView?

cheers

gabriels
2nd February 2006, 18:59
Thanks to KjellKod and Everal,

The problem is that when the header of the QTableView is clicked, the slot sortByColumn which is
the receiver from the signal "sectionClicked" it doesn't do anything.

I can't use the QTableWidget instead of QTableView, because I must use the QSqlQueryModel as a "data source " for the QTableView.

After I have take a loock on the Qt sorces I think that I found the problems:
On the qtableview.cpp I found this :

void QTableView::sortByColumn(int column)
{
Q_D(QTableView);

if (!d->model)
return;
bool ascending = (horizontalHeader()->sortIndicatorSection() == column
&& horizontalHeader()->sortIndicatorOrder() == Qt::DescendingOrder);
Qt::SortOrder order = ascending ? Qt::AscendingOrder : Qt::DescendingOrder;
horizontalHeader()->setSortIndicator(column, order);
d->model->sort(column, order);
}

So, this metod call the model->sort(column,order) of the QSqlQUeryModel (in my case).
Loocking on the documentation from the QSqlQueryModel::sort (...), I found this :

*!
Sorts the model by \a column in the given \a order.

The base class implementation does nothing.
*/
void QAbstractItemModel::sort(int column, Qt::SortOrder order)
{
Q_UNUSED(column);
Q_UNUSED(order);
// do nothing
}

It seems than I must subclassing the sort method...but I don't beleive than to sort a QTableView can be so complicated ..

Thanks ,
Gabriel Strimtu

Everall
3rd February 2006, 13:06
model->setQuery( "SELECT field1,field2 FROM table1" );
You are using not more than 1 table so QSqlTableModel fits your needs?

instead of
QSqlQueryModel *model = new QSqlQueryModel(tableView);
you could use
QSqlTableModel *model = new QSqlTableModel(tableView);
which has
void QSqlTableModel::sort ( int column, Qt::SortOrder order ) [virtual]
implemented

Cheers

gabriels
3rd February 2006, 17:46
model->setQuery( "SELECT field1,field2 FROM table1" );


Thanks Everall,

No, I 'must to use 3 tables on my sql query and for this reason I can't use the QSQlTableModel.Sorry for my wrong SELECT, was just an bad example.
I solve the problem using now the QTableWidget insted of QTableView but I should write code to populate it.
The good news is that in order to sort the QTableWidget I just call :

void setSortingEnabled ( bool enable )
and it is sorted. No more code is necessary :)

I'm sorry for the unimplemented sort metod of the QSqlQueryModel..I think that is a gap .

Regards,
Gabriel Strimtu

swinnenb
1st June 2006, 22:07
Hi

Using Qt 4.1.3 (release, linux)

The actual problem is in QTableView.
It is not possible to enable sorting in QTableView as the actual connect to sortByColumn is made in QTableWidget and not in QtableView.
If you compare this with QTreeView, you'll notice that these connects are moved to QTreeView.
This should be done by Trolltech guys as well for QTableView.
Just compare code difference in qt source where they connect sortByColumn and you'll understand.

BTW: When using sort function in your widget you'll notice that the sort works fine in QTableView. Only the connections when clicking the header are made at the wrong place (In QTableWidget instead of in QTableView).

I hope this explains the original problem in this topic.
And I hope they come with a fix. By the way I did not check snapshot code to see if it is already fixed.

Greetzzzzzz

Bart

jessn
27th April 2010, 11:46
No it is not that complicated, but the name of the class states it is an abstract type as in QAbstractItemModel.

I guess that is the reason why most of the methods have empty implementations or left as pure abstracts.
Alternatively tried to subclass from QStandardItemModel or another more appropriate model if such exists.

Please take a look at the following url

http://cep.xor.aps.anl.gov/software/qt4-x11-4.2.2-browser/d5/d5f/class_q_table_model.html#9c5eb0f558e9549586c86413b 4fa648e



{
QVector<QPair<QTableWidgetItem*, int> > sortable;
QVector<int> unsortable;

sortable.reserve(rowCount());
unsortable.reserve(rowCount());

for (int row = 0; row < rowCount(); ++row) {
if (QTableWidgetItem *itm = item(row, column))
sortable.append(QPair<QTableWidgetItem*,int>(itm, row));
else
unsortable.append(row);
}

LessThan compare = (order == Qt::AscendingOrder ? &itemLessThan : &itemGreaterThan);
qStableSort(sortable.begin(), sortable.end(), compare);

emit layoutAboutToBeChanged();

QVector<QTableWidgetItem*> sorted_table(tableItems.count());
QModelIndexList from;
QModelIndexList to;
for (int i = 0; i < rowCount(); ++i) {
int r = (i < sortable.count()
? sortable.at(i).second
: unsortable.at(i - sortable.count()));
for (int c = 0; c < columnCount(); ++c) {
QTableWidgetItem *itm = item(r, c);
sorted_table[tableIndex(i, c)] = itm;
from << createIndex(r, c, 0);
to << createIndex(i, c, 0);
}
}

tableItems = sorted_table;
changePersistentIndexList(from, to); // ### slow

emit layoutChanged();
}


Please notice the text snippet below taken from the API description.


** void QAbstractItemModel::layoutAboutToBeChanged() [signal]
Since: 4.2
This signal is emitted just before the layout of a model is changed.
Components connected to this signal use it to adapt to changes in the model's layout.

Subclasses should update any persistent model indexes after emitting layoutAboutToBeChanged().

** void QAbstractItemModel::layoutChanged() [signal]
This signal is emitted whenever the layout of items exposed by the model has changed;
for example, when the model has been sorted. When this signal is received by a view,
it should update the layout of items to reflect this change. When subclassing
QAbstractItemModel or QAbstractProxyModel, ensure that you emit layoutAboutToBeChanged()
before changing the order of items or altering the structure of the data you expose to
views, and emit layoutChanged() after changing the layout.

Subclasses should update any persistent model indexes before emitting layoutChanged().


Hth

QTBeginner
24th September 2010, 10:38
How to visualize model data in different way in QTableView

Hi All. I have a model containing in one column floats (ex: 22.7). Now, I want that in QTableView, it will be visualized together with the unit (MB): 22.7 MB. The reason I am doing so is because I want that sorting is based on floats, but the visualization is as I said with units. I created a Model, a Filter and a View. But it does not work. Here is a piece of my code:

QStandardItemModel* model = new QStandardItemModel(this);
QSortFilterProxyModel *filterModel = new QSortFilterProxyModel(0);
filterModel->setSourceModel(model);

QStandardItem* vSItem6 = new QStandardItem();
vSItem6->setData(22.7, Qt:isplayRole);
model->setItem(1, 7, vSItem6);
QModelIndex index = model->index(1, 7, QModelIndex());
QString itext = model->data(index, Qt:isplayRole).toString();
filterModel->setData(index, itext + " MB", Qt:isplayRole);

mUi.tableView->setModel(filterModel);
mUi.tableView->setSortingEnabled(true);
mUi.tableView->show();

Everything seems to be fine, but in QTableView, only the float number is visualized (without the unit MB). In internet everybody is saying to use proxy models, delegates, ... but nobody shows how to do it.
The only way seems to be to write own proxy models and delegates, but I want avoid it. There should be for sure a simple way.
Can anybody please help me? Thanks

NicholasSmith
6th October 2010, 13:00
Have a look at QSortFilterProxyModel, add's a wrapper onto standard models that allows sorting.

Davton
6th October 2010, 16:04
Hi QTBeginner.

You can do that without a filter model.
Just use Qt::DisplayRole AND Qt::UserRole.

Try that :

QStandardItemModel* model = new QStandardItemModel(this);
model->setSortRole(Qt::UserRole);

QStandardItem* vSItem6 = new QStandardItem();
vSItem6->setData("22.7 MB", Qt:DisplayRole); // To be seen in the view
vSItem6->setData(22.7, Qt:UserRole); // To be use in sorting model
model->setItem(1, 7, vSItem6);

mUi.tableView->setModel(model);
mUi.tableView->setSortingEnabled(true);
mUi.tableView->show();

Bye

marcvanriet
6th October 2010, 18:13
Hi gabriels,

I use a tableview on a sqlquery, and I add a SORT statement to my SQL clause when the user presses a column header. It's a lot of work, because you have to see what column header is pressed, what field this relates to, modify the SQL statement, requery the query, ...

But it works. Also I remember the 3 last columns pressed, so a user can sort first by column 1, then column 2, ... etc.

Regards,
Marc