2

I have a simple QTableView with a QSortFilterProxyModel and a source model of a custom TableModel subclass that inherits from QAbstractTableModel. The model is dynamically updated with additional rows.

My problem is this: If I sort the table on a column, then scroll to a specific row, and then more rows are added above this row it pushes the row down. Data is coming in fast enough that it makes it difficult to click on rows to edit them without the row changing underneath my cursor.

Is there a way to stop the table from scrolling and maintain the position of the table relative to say a selected row?

  • I'm afraid this can become tricky. A least workaround could be to remember the "specific row" and use `scrollTo()` after rows have been inserted. A satisfying solution probably needs overloading of `QTableView` or `QAbstractItemView` to re-implement respective layout methods... – Scheff's Cat Feb 25 '17 at 06:46
  • This looks promising: `QTableView::rowViewportPosition()` – Scheff's Cat Feb 25 '17 at 06:50

1 Answers1

3

QTableView::rowViewportPosition() can be used to get the current view port position which has to be corrected if something is inserted before current index.

It can be retrieved before and after insertion of a row using signal handlers.

Thus, the scrolling can be adjusted accordingly in the signal handler after the insertion. This is done changing the value of the vertical scrollbar. (The vertical scroll mode is changed to QTableView::ScrollPerPixel to ensure correct vertical adjustment.)

A minimal code sample:

#include <iostream>

#include <QApplication>
#include <QMainWindow>
#include <QScrollBar>
#include <QStandardItemModel>
#include <QTableView>
#include <QTimer>

enum { NCols = 2 }; // number of columns
enum { Interval = 1000 }; // interval of auto action
enum { NRep = 5 }; // how often selected auto action is repeated

// fills a table model with sample data
void populate(QStandardItemModel &tblModel, bool prepend)
{
  int row = tblModel.rowCount();
  if (prepend) tblModel.insertRow(0);
  for (int col = 0; col < NCols; ++col) {
    QStandardItem *pItem = new QStandardItem(QString("row %0, col %1").arg(row).arg(col));
    tblModel.setItem(prepend ? 0 : row, col, pItem);
  }
}

// does some auto action
void timeout(QTimer &timer, QStandardItemModel &tblModel)
{
  static int step = 0;
  ++step;
  std::cout << "step: " << step << std::endl;
  switch (step / NRep % 3) {
    case 0: break; // pause
    case 1: populate(tblModel, false); break; // append
    case 2: populate(tblModel, true); break; // prepend
  }
}

// managing the non-scrolling when something is inserted.
struct NoScrCtxt {
  QTableView &tblView;
  int y;
  NoScrCtxt(QTableView &tblView_): tblView(tblView_) { }

  void rowsAboutToBeInserted()
  {
    y = tblView.rowViewportPosition(tblView.currentIndex().row());
  }

  void rowsInserted()
  {
    int yNew = tblView.rowViewportPosition(tblView.currentIndex().row());
    if (y != yNew) {
      if (QScrollBar *pScrBar = tblView.verticalScrollBar()) {
        pScrBar->setValue(pScrBar->value() + yNew - y);
      }
    }
  }
};

int main(int argc, char **argv)
{
  QApplication app(argc, argv);
  // build some GUI
  QMainWindow win;
  QStandardItemModel tblModel(0, NCols);
  for (int i = 0; i < 10; ++i) populate(tblModel, false);
  QTableView tblView;
  tblView.setVerticalScrollMode(QTableView::ScrollPerPixel);
  tblView.setModel(&tblModel);
  win.setCentralWidget(&tblView);
  win.show();
  // setup a "no-scroll manager"
  NoScrCtxt ctxt(tblView);
  QObject::connect(&tblModel, &QStandardItemModel::rowsAboutToBeInserted,
    [&ctxt](const QModelIndex&, int, int) { ctxt.rowsAboutToBeInserted(); });
  QObject::connect(&tblModel, &QStandardItemModel::rowsInserted,
    [&ctxt](const QModelIndex&, int, int) { ctxt.rowsInserted(); });
  // initiate some auto action
  QTimer timer;
  timer.setInterval(Interval); // ms
  QObject::connect(&timer, &QTimer::timeout,
    [&timer, &tblModel]() { timeout(timer, tblModel); });
  timer.start();
  // exec. application
  return app.exec();
}

I compiled and tested this in Windows 10, VS2013, Qt 5.7:

Snapshot of sample application

Scheff's Cat
  • 16,517
  • 5
  • 25
  • 45