Smooth QTableView when periodically adding new data
-
I'm building an application similar to WireShark, with data coming in periodic (100-200ms range) frames.
I've notices that when there is more data than table can hold, scroll is not smooth, and moving the complete window isn't smooth either. Disabling the periodic add to the table, makes everything working well again.
I've tried to play with different beforeInsert and afterInsert hooks, but was not successful at all.There is an auto-scroll feature, which scrolls the table if vertical scroll is at the bottom before the insert event.
/* Set tableview model */ ui->table_can_logger->horizontalHeader()->setDefaultAlignment(Qt::AlignmentFlag::AlignLeft); ui->table_can_logger->horizontalHeader()->setStretchLastSection(true); ui->table_can_logger->resizeColumnsToContents(); ui->table_can_logger->resizeRowsToContents(); ui->table_can_logger->setSelectionBehavior(QAbstractItemView::SelectRows); ui->table_can_logger->verticalHeader()->setVisible(true); ui->table_can_logger->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeMode::Custom); ui->table_can_logger->verticalHeader()->setDefaultSectionSize(16); ui->table_can_logger->setShowGrid(false); ui->table_can_logger->setModel(model_can_logger); //Connection for auto scroll connect(model_can_logger, &QAbstractItemModel::rowsInserted, this, &ViewLogger::logger_table_rows_inserted); connect(model_can_logger, &QAbstractItemModel::rowsAboutToBeInserted, this, &ViewLogger::logger_table_rows_to_be_inserted);
Model slots in the view
void ViewLogger::logger_table_rows_to_be_inserted() { QScrollBar* scrollbar = ui->table_can_logger->verticalScrollBar(); do_scroll_table = scrollbar->value() == scrollbar->maximum(); } void ViewLogger::logger_table_rows_inserted() { if (do_scroll_table) { QTimer::singleShot(50, ui->table_can_logger, &QTableView::scrollToBottom); } }
My model append function, which adds new entry to the list, after it has been allocated with
new
:void CANLoggerDataModel::append(CANLoggerDataEntry* entry) { beginInsertRows(QModelIndex(), table_list.count(), table_list.count()); table_list.append(entry); endInsertRows(); }
On every received message, I also have to check for some data, and for this reason I have a backward iterator in the model, too:
void CANLoggerDataModel::canMsgSetSendAck(const ca_can_msg_ack_t* ack) { CANLoggerDataEntry* entry; QListIterator<CANLoggerDataEntry*> it(table_list); uint32_t len = table_list.count(); it.toBack(); while (it.hasPrevious() && len-- > 0) { entry = it.previous(); if (entry->send_id == ack->uid) { entry->status = static_cast<ca_status_t>(ack->status); entry->message.time_sec = ack->time_sec; entry->message.time_usec = ack->time_usec; emit dataChanged(index(len, 0), index(len, columnCount() - 1)); break; } } }
What could cause the lagging events? What could be optimized to improve this?
Thanks
-
@tilz0R
Yeah, tableView/treeView are notoriously slow in this area.
In a case similar to yours,
https://forum.qt.io/post/551198I used a timer to update the view only a few times per second, not each time some data arrived:
// constructeur DumpTreeModel(QTreeView* tree) : TreeItemModel(), _treeView(tree) { connect(this, &QAbstractItemModel::rowsInserted,this, &DumpTreeModel::rowsInserted); /** https://bugreports.qt.io/browse/QTBUG-61763 * QTreeView updates slow down with increasing delay if scrollToBottom is used */ _timer.setInterval(200); _timer.start(); connect(&_timer, &QTimer::timeout, [this] () { static int count=0; int rows=rowCount(QModelIndex()); if(count<rows AND _scrollToBottom) _treeView->scrollToBottom(); count=rows; }); }
Don't get me wrong, it doesn't solve the problem, it only postpone it.