4

I'm using QTableView in Qt 4.8.4 to visualize a lot of data (large/many protein amino acid sequences) and I'd like to be able to make cells as small as possible so I can pack as many as possible into a given window. The problem I'm running into is that when there are many cells displayed at once, everything (e.g. scrolling, resizing, and in general repainting) slows down to a crawl. Here's some sample code (adapted from the examples/tutorials/1_readonly tutorial):

MyModel::MyModel(QObject *parent):QAbstractTableModel(parent){}

int MyModel::rowCount(const QModelIndex & /*parent*/) const {
   return 200;
}
int MyModel::columnCount(const QModelIndex & /*parent*/) const {
    return 60;
}
QVariant MyModel::data(const QModelIndex &index, int role) const {
    if (role == Qt::DisplayRole){
       return QString("%1").arg(index.row()%10);
    }
    return QVariant();
}

and here's the code which runs the table view:

int main(int argc, char *argv[]){
   QApplication a(argc, argv);
   QTableView tableView;    
   tableView.horizontalHeader()->setDefaultSectionSize(15);
   tableView.verticalHeader()->setDefaultSectionSize(15);
   tableView.setFont(QFont("Courier",12));
   MyModel myModel(0);
   tableView.setModel( &myModel );
   tableView.setGeometry(0,0,1000,1000);
   tableView.show();
   return a.exec();
}

When I use Instruments on OSX while scrolling up and down, it's spending a lot of time in QWidgetPrivate::drawWidget and down the stack, QWidgetPrivate::paintSiblingsRecursive... i.e., it's spending a lot of time redrawing my table.

I'm new to Qt, so I'm not sure how to approach this problem. Should I:

  • override the paint method? i.e. perhaps I could save my whole table as an image, and when scrolling happens, to just repaint the image until movement stops (and then return to painting the table directly)?
  • Not use tables in Qt at all? Perhaps I can just use a Text field to accomplish my purposes? e.g. for each letter in the text, i'd like hovertext, selections, coloring letter's backgrounds, etc.

Both of these options seem like a lot of work to make up for ground lost by switching away from QTableView. Are there any other suggestions?

amos
  • 5,092
  • 4
  • 34
  • 43
  • 1
    Why do you need a table? For editing? If you need just a visualization, you can simply draw your data. – vahancho Oct 30 '13 at 20:29

3 Answers3

6

Try to use QTreeView, but set uniformRowHeights to true. Millions of items worked last time I've checked.

EDIT: QTreeView supports tables and more!

user1095108
  • 14,119
  • 9
  • 58
  • 116
  • Thanks for your thoughts, @user1095108. I tried your suggestion using `setColumnWidth` to make all the columns visible (and `uniformRowHeights`) but that was similarly slow. The issue doesn't seem to be the total amount of data per say, but rather the amount of work necessary to paint a window (which both views will need to do). Incidentally, I loaded similar data into an MS Excel spreadsheet, and it was also slow. – amos Oct 30 '13 at 20:42
  • 1
    10 columns isn't much, you probably did something wrong. Keep trying, perhaps. The `uniformRowHeights` trick is discussed often. Google. – user1095108 Oct 30 '13 at 22:27
5

QTableView is known to be slow when dealing with large datasets. I suggest you to switch to Qt Graphics View Framework. It's much more efficient and is flexible enough to display a table.

QGraphicsScene scene;
QFont font("Courier",12);
QFontMetrics font_metrics(font);
int padding = 2;
int column_width = font_metrics.width("X") + padding * 2;
int row_height = font_metrics.height() + padding * 2;
int rows = 200, columns = 60;
for(int x = 0; x < columns; x++) {
  for(int y = 0; y < rows; y++) {
    QGraphicsSimpleTextItem* item = scene.addSimpleText(QString().setNum(y % 10), font);
    item->setPos(x * column_width + padding, y * row_height + padding);
  }
}
for(int x = 0; x < columns + 1; x++) {
  int line_x = x * column_width;
  scene.addLine(line_x, 0, line_x, rows * row_height)->setPen(QPen(Qt::gray));
}
for(int y = 0; y < rows + 1; y++) {
  int line_y = y * row_height;
  scene.addLine(0, line_y, columns * column_width, line_y)->setPen(QPen(Qt::gray));
}
QGraphicsView view(&scene);
view.resize(700, 700);
view.show();
Pavel Strakhov
  • 39,123
  • 5
  • 88
  • 127
  • As far as I can tell, this is the solution I was looking for -- it's noticeably faster than QTableView. If I push the limits on this approach, it's also sluggish, but it's unreasonable to expect something like this to be as fast as raw text. Incidentally, this also solves the other problem I was having about text spacing within cells. – amos Oct 31 '13 at 17:04
  • @amos You probably need OpenGL rendering then. Hence, I advise you not to go this route, but focus on the new OpenGL-based SceneGraph API and Qt Quick 2. – user1095108 Oct 31 '13 at 22:34
0

i'm using a 1e8 rows table and had to switch to QTreeView with setUniformRowHeights(true);

roberto
  • 577
  • 6
  • 5