FumbleFingers
FumbleFingers

Reputation: 234

Accessing Qt tableView from MyModel

(Linux Mint QT5) I subclassed QAbstractTableModel to use a custom sort() function after tableView.setModel(MyModel)...

class MyModel : public QAbstractTableModel
{   Q_OBJECT
public:
    MyModel(QTableView *_tableview);    // sort() function needs to access the linked tableview
... (more function definitions)
    void sort(int column, Qt::SortOrder order) override;
private:
QTableView *tableview;  // <<<======== Don't know how to avoid passing and storing this pointer
};

MyModel::MyModel(QTableView *_tableview) : QAbstractTableModel(0)
{
tableview=_tableview;
... (more constructor code)
}

void MyModel::sort(int column, Qt::SortOrder order)
{
int uniq=data(tableview->currentIndex().siblingAtColumn(4), Qt::DisplayRole).toInt();
sort_redirection_table(column, order);  // sort pointers into data, not the data itself
for (int row=emk->ct; row--; ) // now re-locate current row
    if ((data(QAbstractTableModel::index(row, 4), Qt::DisplayRole)).toInt()==uniq)
        {
        tableview->scrollTo(QAbstractTableModel::index(row, column),QTreeView::PositionAtCenter);
        tableview->selectRow(row);  // make tableView re-focus around same item as before sorting
        break;
        }
}

Note that MyModel::data() accesses the underlying data through a sorted array of pointers. Every (int) value in column 4 is unique, so I'm using currentIndex().siblingAtColumn(4) from the linked tableView to see which line item was selected before the sort, because I need to re-centre the display around that line after sorting.


My code seems to work fine, but I can't help feeling it's "inelegant" to pass the tableView pointer to MyModel constructor, storing it for later use when re-focusing the display after sorting.

This is my first Qt project, so I'm certainly no expert! I started with dummy copies of MyProject/main.cpp, mymodel.cpp, mymodel.h against which I ran qmake -project followed by qmake MyProject.pro to create makefile. So far I'm only using QtCreator to edit/compile my own "bare metal" code (I haven't even looked at GUI design mode facilities yet).

Am I missing something trivial about MyModel's access to the linked tableView? Is there any easy way to re-focus the display without that stored pointer? Or some way to get the pointer without having it passed to the constructor? Or am I simply mistaken in thinking my current code is 'inelegant'?

Upvotes: 0

Views: 347

Answers (1)

SteakOverflow
SteakOverflow

Reputation: 2033

Complex question, but I'm going to try to shed some light on different aspects.

  1. currentIndex and the selection are two separate (but not unrelated) things. Make sure you understand the difference when working with both.

  2. You are trying to sort an item model. In my experience, it is always best to not do that in the actual item model, but use or extend a QSortFilterProxyModel.

  3. Your sort function is missing a few things: Signals for the view, and persistent index updates. By default, QSortFilterProxyModel handles all that for you. The documentation lists these actions:

  • Emit the layoutAboutToBeChanged() signal
  • Update internal data which represents the structure of the model.
  • Update persistent indexes using changePersistentIndexList()
  • Emit the layoutChanged() signal.
  1. You don't have to access the table view from the model. That's what signals are for. If you don't find any other solution, you can always define a new sorted signal in the model and then connect to some function that scrolls to the element outside of the model.

  2. Putting most of this together, here is an example on what you could do. If the default sorting isn't sophisticated enough, extend QSortFilterProxyModel and use that instead. The following would be somewhere in the setup of the widget that contains the table view:

    MyModel* myModel = new MyModel(tableView);
    QSortFilterProxyModel* proxyModel = new QSortFilterProxyModel(tableView);
    proxyModel->setSourceModel(myModel);
    tableView->setModel(proxyModel);
    connect(proxyModel, &QSortFilterProxyModel::layoutChanged, tableView, [tableView]()
    {
        tableView->scrollTo(tableView->currentIndex());
    });

Upvotes: 1

Related Questions