QAbstractTableModel中的data()到底执行几遍???

本文探讨了QAbstractTableModel中data()函数执行的次数问题。通过测试发现,data()函数实际上执行了3次,每次遍历都会为每一行每一项的七个角色赋值。问题源于QTableView的paintEvent()函数,该函数在绘制表格时调用data()。对于为何遍历三次的原因,文中提到可能与Qt内部的逻辑有关,但具体原因尚不明确。如果你知道其中原理,可以通过评论分享。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

有一个问题:QAbstractTableModel中的data()函数到底执行几遍???

 

 

发现问题的过程

 1、一个普通的继承 QAbstractTableModel 的类

 

 

class CurrencyModel : public QAbstractTableModel  
{  
public:  
    CurrencyModel(QObject *parent = 0);  
  
    void setCurrencyMap(const QMap<QString, double> &map);  
    int rowCount(const QModelIndex &parent) const;  
    int columnCount(const QModelIndex &parent) const;  
    QVariant data(const QModelIndex &index, int role) const;  
    QVariant headerData(int section, Qt::Orientation orientation,  
                        int role) const;  
  
private:  
    QString currencyAt(int offset) const;  
  
    QMap<QString, double> currencyMap;  
};  

 

 

 2、其中的重载的data()函数如下:

 

//返回一个项的任意角色的值,这个项被指定为QModelIndex
QVariant MoReconQueue::data(const QModelIndex &index, int role) const
{
	qDebug() <<"role:"<< role<< "index : " << index.row() << index.column();
    //模型索引无效,返回空值
    if (!index.isValid())
        return QVariant();
    //对其角色
    if (role == Qt::TextAlignmentRole)
    {
        return int(Qt::AlignRight | Qt::AlignVCenter);
    }
    //显示角色
    else if (role == Qt::DisplayRole)
    {
		
        return reconQueueAt(index.row(),index.column());

    }
	
    //返回空值
    return QVariant();
}
 

 

3、测试结果:

发现data()执行了3次遍历,每次遍历都执行每一行每一项的七个角色的赋值。

 

 

role: 6 index :  0 0

role: 7 index :  0 0

role: 9 index :  0 0

role: 10 index :  0 0

role: 1 index :  0 0

role: 0 index :  0 0

role: 8 index :  0 0 

 

 

 

 

我就纳闷了,执行一次遍历就够了,为啥要执行三遍呢。

 

Qt项数据角色如下:

 

enum Qt::ItemDataRole

Each item in the model has a set of data elements associated with it, each with its own role. The roles are used by the view to indicate to the model which type of data it needs. Custom models should return data in these types.

The general purpose roles (and the associated types) are:

ConstantValueDescription
Qt::DisplayRole0The key data to be rendered in the form of text. (QString)
Qt::DecorationRole1The data to be rendered as a decoration in the form of an icon. (QColorQIcon or QPixmap)
Qt::EditRole2The data in a form suitable for editing in an editor. (QString)
Qt::ToolTipRole3The data displayed in the item's tooltip. (QString)
Qt::StatusTipRole4The data displayed in the status bar. (QString)
Qt::WhatsThisRole5The data displayed for the item in "What's This?" mode. (QString)
Qt::SizeHintRole13The size hint for the item that will be supplied to views. (QSize)

Roles describing appearance and meta data (with associated types):

ConstantValueDescription
Qt::FontRole6The font used for items rendered with the default delegate. (QFont)
Qt::TextAlignmentRole7The alignment of the text for items rendered with the default delegate. (Qt::AlignmentFlag)
Qt::BackgroundRole8The background brush used for items rendered with the default delegate. (QBrush)
Qt::BackgroundColorRole8This role is obsolete. Use BackgroundRole instead.
Qt::ForegroundRole9The foreground brush (text color, typically) used for items rendered with the default delegate. (QBrush)
Qt::TextColorRole9This role is obsolete. Use ForegroundRole instead.
Qt::CheckStateRole10This role is used to obtain the checked state of an item. (Qt::CheckState)

Accessibility roles (with associated types):

ConstantValueDescription
Qt::AccessibleTextRole11The text to be used by accessibility extensions and plugins, such as screen readers. (QString)
Qt::AccessibleDescriptionRole12A description of the item for accessibility purposes. (QString)

User roles:

ConstantValueDescription
Qt::UserRole32The first role that can be used for application-specific purposes.

 

问题分析

 

 

1、经调试跟踪,Qt中的qtableview.h里面进行调用我们自定义的Modle


其中paint函数负责调用data()函数,我也很闷为啥绿色代码会遍历3次呢???那个Rects到底是什么值呢。。。其中的原理,我暂时还没搞明白。如果有知道的朋友,可以留言告诉我。谢谢

 

 

/*!

    Paints the table on receipt of the given paint event \a event.

*/

void QTableView::paintEvent(QPaintEvent *event)

{

    Q_D(QTableView);

    // setup temp variables for the painting

    QStyleOptionViewItemV4 option = d->viewOptionsV4();

    const QPoint offset = d->scrollDelayOffset;

    const bool showGrid = d->showGrid;

    const int gridSize = showGrid ? 1 : 0;

    const int gridHint = style()->styleHint(QStyle::SH_Table_GridLineColor, &option, this);

    const QColor gridColor = static_cast<QRgb>(gridHint);

    const QPen gridPen = QPen(gridColor, 0, d->gridStyle);

    const QHeaderView *verticalHeader = d->verticalHeader;

    const QHeaderView *horizontalHeader = d->horizontalHeader;

    const QStyle::State state = option.state;

    const bool alternate = d->alternatingColors;

    const bool rightToLeft = isRightToLeft();

 

    QPainter painter(d->viewport);

 

    // if there's nothing to do, clear the area and return

    if (horizontalHeader->count() == 0 || verticalHeader->count() == 0 || !d->itemDelegate)

        return;

 

    uint x = horizontalHeader->length() - horizontalHeader->offset() - (rightToLeft ? 0 : 1);

    uint y = verticalHeader->length() - verticalHeader->offset() - 1;

 

    const QRegion region = event->region().translated(offset);

    const QVector<QRect> rects = region.rects();

 

    //firstVisualRow is the visual index of the first visible row.  lastVisualRow is the visual index of the last visible Row.

    //same goes for ...VisualColumn

    int firstVisualRow = qMax(verticalHeader->visualIndexAt(0),0);

    int lastVisualRow = verticalHeader->visualIndexAt(verticalHeader->viewport()->height());

    if (lastVisualRow == -1)

        lastVisualRow = d->model->rowCount(d->root) - 1;

 

    int firstVisualColumn = horizontalHeader->visualIndexAt(0);

    int lastVisualColumn = horizontalHeader->visualIndexAt(horizontalHeader->viewport()->width());

    if (rightToLeft)

        qSwap(firstVisualColumn, lastVisualColumn);

    if (firstVisualColumn == -1)

        firstVisualColumn = 0;

    if (lastVisualColumn == -1)

        lastVisualColumn = horizontalHeader->count() - 1;

 

    QBitArray drawn((lastVisualRow - firstVisualRow + 1) * (lastVisualColumn - firstVisualColumn + 1));

 

    if (d->hasSpans()) {

        d->drawAndClipSpans(region, &painter, option, &drawn,

                             firstVisualRow, lastVisualRow, firstVisualColumn, lastVisualColumn);

    }

 

    for (int i = 0; i < rects.size(); ++i) {

        QRect dirtyArea = rects.at(i);

        dirtyArea.setBottom(qMin(dirtyArea.bottom(), int(y)));

        if (rightToLeft) {

            dirtyArea.setLeft(qMax(dirtyArea.left(), d->viewport->width() - int(x)));

        } else {

            dirtyArea.setRight(qMin(dirtyArea.right(), int(x)));

        }

 

        // get the horizontal start and end visual sections

        int left = horizontalHeader->visualIndexAt(dirtyArea.left());

        int right = horizontalHeader->visualIndexAt(dirtyArea.right());

        if (rightToLeft)

            qSwap(left, right);

        if (left == -1) left = 0;

        if (right == -1) right = horizontalHeader->count() - 1;

 

        // get the vertical start and end visual sections and if alternate color

        int bottom = verticalHeader->visualIndexAt(dirtyArea.bottom());

        if (bottom == -1) bottom = verticalHeader->count() - 1;

        int top = 0;

        bool alternateBase = false;

        if (alternate && verticalHeader->sectionsHidden()) {

            uint verticalOffset = verticalHeader->offset();

            int row = verticalHeader->logicalIndex(top);

            for (int y = 0;

                 ((uint)(y += verticalHeader->sectionSize(top)) <= verticalOffset) && (top < bottom);

                 ++top) {

                row = verticalHeader->logicalIndex(top);

                if (alternate && !verticalHeader->isSectionHidden(row))

                    alternateBase = !alternateBase;

            }

        } else {

            top = verticalHeader->visualIndexAt(dirtyArea.top());

            alternateBase = (top & 1) && alternate;

        }

        if (top == -1 || top > bottom)

            continue;

 

        // Paint each row item

        for (int visualRowIndex = top; visualRowIndex <= bottom; ++visualRowIndex) {

            int row = verticalHeader->logicalIndex(visualRowIndex);

            if (verticalHeader->isSectionHidden(row))

                continue;

            int rowY = rowViewportPosition(row);

            rowY += offset.y();

            int rowh = rowHeight(row) - gridSize;

 

            // Paint each column item

            for (int visualColumnIndex = left; visualColumnIndex <= right; ++visualColumnIndex) {

                int currentBit = (visualRowIndex - firstVisualRow) * (lastVisualColumn - firstVisualColumn + 1)

                        + visualColumnIndex - firstVisualColumn;

 

                if (currentBit < 0 || currentBit >= drawn.size() || drawn.testBit(currentBit))

                    continue;

                drawn.setBit(currentBit);

 

                int col = horizontalHeader->logicalIndex(visualColumnIndex);

                if (horizontalHeader->isSectionHidden(col))

                    continue;

                int colp = columnViewportPosition(col);

                colp += offset.x();

                int colw = columnWidth(col) - gridSize;

 

                const QModelIndex index = d->model->index(row, col, d->root);

                if (index.isValid()) {

                    option.rect = QRect(colp + (showGrid && rightToLeft ? 1 : 0), rowY, colw, rowh);

                    if (alternate) {

                        if (alternateBase)

                            option.features |= QStyleOptionViewItemV2::Alternate;

                        else

                            option.features &= ~QStyleOptionViewItemV2::Alternate;

                    }

                    d->drawCell(&painter, option, index);

                }

            }

            alternateBase = !alternateBase && alternate;

        }

 

        if (showGrid) {

            // Find the bottom right (the last rows/columns might be hidden)

            while (verticalHeader->isSectionHidden(verticalHeader->logicalIndex(bottom))) --bottom;

            QPen old = painter.pen();

            painter.setPen(gridPen);

            // Paint each row

            for (int visualIndex = top; visualIndex <= bottom; ++visualIndex) {

                int row = verticalHeader->logicalIndex(visualIndex);

                if (verticalHeader->isSectionHidden(row))

                    continue;

                int rowY = rowViewportPosition(row);

                rowY += offset.y();

                int rowh = rowHeight(row) - gridSize;

                painter.drawLine(dirtyArea.left(), rowY + rowh, dirtyArea.right(), rowY + rowh);

            }

 

            // Paint each column

            for (int h = left; h <= right; ++h) {

                int col = horizontalHeader->logicalIndex(h);

                if (horizontalHeader->isSectionHidden(col))

                    continue;

                int colp = columnViewportPosition(col);

                colp += offset.x();

                if (!rightToLeft)

                    colp +=  columnWidth(col) - gridSize;

                painter.drawLine(colp, dirtyArea.top(), colp, dirtyArea.bottom());

            }

 

            //draw the top & left grid lines if the headers are not visible.

            //We do update this line when subsequent scroll happen (see scrollContentsBy)

            if (horizontalHeader->isHidden() && verticalScrollMode() == ScrollPerItem)

                painter.drawLine(dirtyArea.left(), 0, dirtyArea.right(), 0);

            if (verticalHeader->isHidden() && horizontalScrollMode() == ScrollPerItem)

                painter.drawLine(0, dirtyArea.top(), 0, dirtyArea.bottom());

            painter.setPen(old);

        }

}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值