Shuffling the items on QtableView
-
I made the following model/view structure.
mymodel=new QAbstractTableModel;
proxyModel = new StarSortFilterProxyModel();
proxyModel->setDynamicSortFilter(true);
tableView=new QTableView(this);
tableView->setModel(proxyModel);I want to shuffle the order of items on tableview without changing the order of items on base model(mymodel). Can anyone explain how I can randomly order it? It seems I need to shuffle the order of indexes of proxyModel. Thank you.
-
Hi and welcome to devnet,
You need to implement your own QSortFilterProxyModel that will do the shuffling.
-
protected: bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
You can use std::random to determine false and true randomly.
bool some_class::lessThan(const QModelIndex&, const QModelIndex&) const { return dis(gen) < 1; }
The example of std::random(full version locate at here)
#include <random> #include <iostream> int main() { std::random_device rd; std::mt19937 gen(rd()); std::uniform_int_distribution<> dis(0, 1); for (int n=0; n<10; ++n) std::cout << dis(gen) << ' '; std::cout << '\n'; }
random_device may or may not generate random seed(unless it do not work for mingw5.3), in this case qrand() could be a replacement.
-
I had a similar problem a couple of months ago and @VRonin suggested I take a look at the KDE API. https://api.kde.org/frameworks/kitemmodels/html/classKExtraColumnsProxyModel.html. While I did not use it directly, I did use the techniques in there to build a custom class that did just what you ask.
// reorderColProxyModel.h #pragma once #include "constants.h" #include <QObject> #include <QIdentityProxyModel> class ReOrderColProxyModel : public QIdentityProxyModel { public: ReOrderColProxyModel(QObject *parent = Q_NULLPTR); ~ReOrderColProxyModel() = default; QVariant data(const QModelIndex &proxyIndex, int role) const; QVariant headerData(int section, Qt::Orientation orientation, int role) const; protected: int columnCount(const QModelIndex &) const; private: constexpr static int _size= 15; // list columns in order to be seen REPAIR_STATUS_COLUMN _forwardLookup[_size] { REPAIR_STATUS_COLUMN::RMA_NUMBER, REPAIR_STATUS_COLUMN::WORKDAYS, REPAIR_STATUS_COLUMN::CUSTOMER_NAME, REPAIR_STATUS_COLUMN::LOCATION, REPAIR_STATUS_COLUMN::MODEL, REPAIR_STATUS_COLUMN::RMA_ISSUE_DATE, REPAIR_STATUS_COLUMN::RCVD_DATE, REPAIR_STATUS_COLUMN::DONE_DATE, REPAIR_STATUS_COLUMN::SHIP_DATE, REPAIR_STATUS_COLUMN::CURRENT_STATUS, REPAIR_STATUS_COLUMN::SPECIAL_NOTES, REPAIR_STATUS_COLUMN::TECH, REPAIR_STATUS_COLUMN::QB_NOTES, REPAIR_STATUS_COLUMN::RMA_NOTES, REPAIR_STATUS_COLUMN::RMA_UNIT_NOTES }; };
// reorderColProxyModel.cpp #include "reorderColProxyModel.h" //---------------------------------------------------------------------- ReOrderColProxyModel::ReOrderColProxyModel(QObject *parent) :QIdentityProxyModel(parent) {} //---------------------------------------------------------------------- QVariant ReOrderColProxyModel::data(const QModelIndex &proxyIndex, int role) const { int row= proxyIndex.row(); int col= proxyIndex.column(); QModelIndex ix= sourceModel()->index(row,static_cast<int>(_forwardLookup[col])); return ix.data(role); } //---------------------------------------------------------------------- QVariant ReOrderColProxyModel::headerData(int section, Qt::Orientation orientation, int role) const { return sourceModel()->headerData(static_cast<int>(_forwardLookup[section]),orientation,role); } //---------------------------------------------------------------------- int ReOrderColProxyModel::columnCount(const QModelIndex &) const { return _size; }
Where REPAIR_STATUS_COLUMN is an enum of the columns in the table. _forwardLookup is in the order that you want the columns to appear. Being a proxymodel, you just set the source model and use it to display the columns in the order you like.
You should look at the code in the link. It is much more generalised and capable than this and just good code to learn from.
Edit:
The above link is not the solution to your problem. My original problem was two-fold. First I had to add a computed column which wouldn't reflect back into the original model then I had to reorder the columns. The link to the class which did the re-ordering is here: https://api.kde.org/frameworks/kitemmodels/html/classKRearrangeColumnsProxyModel.htmlYou will notice that it subclasses QIdentityProxyModel which is a better fit than QSortFilterProxyModel.
I ended up using a simplified version of each class, implementing only the bare necessities, but I only had a single use. YMMV
Mike
-
Thank you very much. It works.
I created extra shuffle_colmun in base model.
Instead of std::random() I simply used rand() to generate integer between 0-20. So the result rand()%20 < 10 is half true and half false. It means if I sort contents by shuffle_colmun, it shuffles the contents without changing the order of original base model.class MySortFilterProxyModel : public QSortFilterProxyModel
{
Q_OBJECTpublic:
MySortFilterProxyModel(){}protected:
bool lessThan(const QModelIndex &left, const QModelIndex &right) const
{
if(left.column()== shuffle_column)
return rand()%20 < 10;
else
return QSortFilterProxyModel::lessThan(left, right);
}
};void shuffling()
{
if(tableView->horizontalHeader()->sortIndicatorOrder()==Qt::DescendingOrder)
tableView->sortByColumn(shuffle_column, Qt::AscendingOrder);
else
tableView->sortByColumn(shuffle_column, Qt::DescendingOrder);
} -
You can simplify the shuffling function:
void shuffling() { tableView->sortByColumn(shuffle_column, tableView->horizontalHeader()->sortIndicatorOrder()); }