PDA

View Full Version : QTableView paints too much



Jimmy2775
26th July 2006, 00:55
I have a GUI with a series of textboxes and a QTableView. Whenever the user clicks on a row, the textboxes will display the values of each column in the row, allowing the user to edit the contents.

When the user edits the contents of a textbox, I determine the index of the row being edited and refresh the row from my QAbstractTableModel:
void TableModel::refreshRow( const QModelIndex aModelIndex )
{
QModelIndex rowFirstColumn = index( aModelIndex.row(), 0, QModelIndex() );
QModelIndex rowLastColumn = index( aModelIndex.row(), ( columnCount() - 1 ), QModelIndex() );
emit dataChanged( rowFirstColumn, rowLastColumn );
}
Due to design decisions beyond my control and outside the scope of this issue, I cannot use the QAbstractTableModel's setData method when I'm setting data from the textboxes - that's why I've written my own refresh method.

Anyway, the problem I'm having is that after the dataChanged signal is handled by the QTableView, the entire table is redrawn again and I can't figure out what is causing that to happen. The result is that when the user types a letter in the textbox, there is a noticable lag between the keypress and the character appearing in the textbox and on the QTableView.

I was able to determine that the entire table was being redrawn by putting a breakpoint in my QAbstractTableModel's data method, and I can see the method being called for all the visible cell indexes in the table, at least once for each role. Here is the bottom part of the stack trace at that point:
> nrcs.exe!avid::nrcs::ui::model::TableModel::data(c onst QModelIndex & index={...}, int role=0) Line 151 C++
QtGuid4.dll!QSortFilterProxyModel::data(const QModelIndex & index={...}, int role=0) Line 652 + 0x1d C++
QtCored4.dll!QModelIndex::data(int arole=0) Line 321 + 0x4b C++
QtGuid4.dll!QItemDelegate::paint(QPainter * painter=0x0012cbd8, const QStyleOptionViewItem & option={...}, const QModelIndex & index={...}) Line 238 + 0x12 C++
QtGuid4.dll!QTableView::paintEvent(QPaintEvent * event=0x0012d348) Line 448 C++
QtGuid4.dll!QWidget::event(QEvent * event=0x0012d348) Line 5121 C++
QtGuid4.dll!QFrame::event(QEvent * e=0x0012d348) Line 598 C++
QtGuid4.dll!QAbstractScrollArea::viewportEvent(QEv ent * e=0x0012d348) Line 476 + 0xc C++
QtGuid4.dll!QAbstractItemView::viewportEvent(QEven t * event=0x0012d348) Line 969 C++
QtGuid4.dll!QAbstractScrollAreaPrivate::viewportEv ent(QEvent * e=0x0012d348) Line 91 + 0x26 C++
QtGuid4.dll!QAbstractScrollAreaViewport::event(QEv ent * e=0x0012d348) Line 103 + 0xf C++
QtGuid4.dll!QApplicationPrivate::notify_helper(QOb ject * receiver=0x0ac1d0a0, QEvent * e=0x0012d348) Line 3173 + 0xf C++
QtGuid4.dll!QApplication::notify(QObject * receiver=0x0ac1d0a0, QEvent * e=0x0012d348) Line 3134 + 0x10 C++
QtCored4.dll!QCoreApplication::sendSpontaneousEven t(QObject * receiver=0x0ac1d0a0, QEvent * event=0x0012d348) Line 174 + 0x3e C++
QtGuid4.dll!qt_sendSpontaneousEvent(QObject * receiver=0x0ac1d0a0, QEvent * event=0x0012d348) Line 1228 + 0xe C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 840 + 0xd C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=2, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=6, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=1, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=0, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=2, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=0, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=4, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=0, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=2, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 767 + 0x20 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=3, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 767 + 0x20 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=1, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=1, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=0, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::paintSiblingsRecu rsive(QPaintDevice * pdev=0x03053a10, const QList<QObject *> & siblings={...}, int index=55, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=4) Line 777 C++
QtGuid4.dll!QWidgetPrivate::drawWidget(QPaintDevic e * pdev=0x03053a10, const QRegion & rgn={...}, const QPoint & offset={...}, int flags=5) Line 870 + 0x28 C++
QtGuid4.dll!QWidgetBackingStore::cleanRegion(const QRegion & rgn={...}, QWidget * widget=0x09f06920, bool recursiveCopyToScreen=true) Line 697 C++
QtGuid4.dll!qt_syncBackingStore(QRegion rgn={...}, QWidget * widget=0x09f06920, bool recursive=true) Line 220 C++
QtGuid4.dll!QETWidget::translatePaintEvent(const tagMSG & msg={...}) Line 3445 + 0x2b C++
QtGuid4.dll!QtWndProc(HWND__ * hwnd=0x00220a3c, unsigned int message=49687, unsigned int wParam=0, long lParam=0) Line 1439 + 0xc C++

Any ideas what is causing this to happen and what I can do to improve performance?

wysota
26th July 2006, 01:48
As far as I understand the code responsible for updating the view, it looks like the view only checks whether you update one cell or more. In the first case, it only updates that single item. Otherwise it just asks the viewport to update itself causing all visible data to be reread.

Here is the code:

void QAbstractItemView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight)
{
// Single item changed
Q_D(QAbstractItemView);
if (topLeft == bottomRight && topLeft.isValid()) {
if (d->hasEditor(topLeft))
itemDelegate()->setEditorData(d->editorForIndex(topLeft), topLeft);
else if (isVisible() && !d->delayedLayout.isActive()) // otherwise the items will be update later anyway
d->viewport->update(visualRect(topLeft));
return;
}
updateEditorData(); // we are counting on having relatively few editors
if (!isVisible() || d->delayedLayout.isActive())
return; // no need to update
d->viewport->update();
}

You might want to subclass and reimplement this method to only update this part which did actually change (you need to change the last line of this method to take the appropriate rectange as a parameter).

Jimmy2775
26th July 2006, 18:42
That sounds like it would work, but when I tried to implement that function I got compiler errors starting at the statement Q_D(QAbstractItemView); - 'QTableView::d_func' : cannot access private member declared in class 'QTableView'. I have to apoligize here but I am new to both Qt and C++, so while I realize that this is related to the private d pointer, I don't fully understand what's happening here or how to make my derived class work. Is there anything written on the internet that can enlighten me on this subject?

You pointed out that the view will update either individual cells, or the entire table, so for now I've created a loop and emit dataChanged signals for each cell in the row. This has improved performance dramatically, but I would eventually like to implement the solution you suggested wysota.