有一个问题: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:

Constant Value Description
Qt::DisplayRole 0 The key data to be rendered in the form of text. (QString)
Qt::DecorationRole 1 The data to be rendered as a decoration in the form of an icon. (QColor, QIcon or QPixmap)
Qt::EditRole 2 The data in a form suitable for editing in an editor. (QString)
Qt::ToolTipRole 3 The data displayed in the item's tooltip. (QString)
Qt::StatusTipRole 4 The data displayed in the status bar. (QString)
Qt::WhatsThisRole 5 The data displayed for the item in "What's This?" mode. (QString)
Qt::SizeHintRole 13 The size hint for the item that will be supplied to views. (QSize)

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

Constant Value Description
Qt::FontRole 6 The font used for items rendered with the default delegate. (QFont)
Qt::TextAlignmentRole 7 The alignment of the text for items rendered with the default delegate. (Qt::AlignmentFlag)
Qt::BackgroundRole 8 The background brush used for items rendered with the default delegate. (QBrush)
Qt::BackgroundColorRole 8 This role is obsolete. Use BackgroundRole instead.
Qt::ForegroundRole 9 The foreground brush (text color, typically) used for items rendered with the default delegate. (QBrush)
Qt::TextColorRole 9 This role is obsolete. Use ForegroundRole instead.
Qt::CheckStateRole 10 This role is used to obtain the checked state of an item. (Qt::CheckState)

Accessibility roles (with associated types):

Constant Value Description
Qt::AccessibleTextRole 11 The text to be used by accessibility extensions and plugins, such as screen readers. (QString)
Qt::AccessibleDescriptionRole 12 A description of the item for accessibility purposes. (QString)

User roles:

Constant Value Description
Qt::UserRole 32 The 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);

}

}

QAbstractTableModel中的data()到底执行几遍???相关推荐

  1. Jmeter===Jmeter中使用CSV Data Set Config参数化不重复数据执行N遍(转)

    Jmeter中使用CSV Data Set Config参数化不重复数据执行N遍 要求: 今天要测试上千条数据,且每条数据要求执行多次,(模拟多用户多次抽奖) 1.用户id有175个,且没有任何排序规 ...

  2. LF AI Data基金会执行董事Ibrahim Haddad:加速中的开源人工智能创新与合作

    以人工智能为代表的新一代信息技术正在深刻改变着世界,改变着人类生活.人工智能技术不但能够带来便利,同时也为其带来了不确定.不稳定等诸多挑战. 2022年7月21日,由中国开源软件推进联盟主办,赛迪传媒 ...

  3. 什么是mysql的游标_数据库中的游标到底是什么意思

    数据库中的游标到底是什么意思 关注:177  答案:2  mip版 解决时间 2021-01-15 20:54 提问者更无风月 2021-01-15 15:53 数据库中的游标到底是什么意思 最佳答案 ...

  4. 领域驱动架构(DDD)建模中的模型到底是什么? 1

    领域驱动架构(DDD)建模中的模型到底是什么?    前言 叙述 DDD本身是一套完整.详尽的方法论,从如何需求沟通(构建领域知识),到高层设计(战略建模).详细设计(战术建模),细致到代码的实现风格 ...

  5. java boolean几个字节_Java中boolean类型到底占用多少个字节?

    1.时间:2017-07-03 07:37:06YuanMxy 2.问题描述:今天在复习java基础的时候发现一小问题,Java中boolean类型到底占用多少个字节? 3.问题解答: (1)什么是b ...

  6. java socket中属性详解_前端开发:关于Vue组件中的data属性值是函数而不是对象的详解...

    最近在搞关于前端开发的基础知识归纳,发现了不少经典知识点,那么本篇博文就来分享一个经典的知识点:Vue组件中的data属性值为什么是函数而不是对象.首先来了解一下Vue组件的使用理念:在Vue组件使用 ...

  7. Java中finally和return执行顺序

    思考一个问题 Java异常捕获机制try-catch-finally块中的finally语句是否一定会被执行?起码在以下两种情况下是不会被执行的: 1.在try之前就返回了,try没有执行到. 2.t ...

  8. JBoss 系列八十一: jBPM 6 中使用 jbpm-console 创建执行 BPM 流程 - II

    2019独角兽企业重金招聘Python工程师标准>>> 概述 如jBPM 6 中使用 jbpm-console 创建执行 BPM 流程 - I中所示,我们在jbpm-console ...

  9. eclipse工具连接mysql_eclipse工具中使用Data Source Explorer连接数据库(MySQL)

    1.进入Eclipse工具,打开Data Source Explorer.Window==>Show View==>Data Source Explorer(注:如果找不到请选择Other ...

最新文章

  1. java 进程睡眠_Linux进程的睡眠和唤醒简析
  2. 高精度惯性传感器如何实现全球自动化愿景?
  3. [译]ASP.NET Core 2.0 网址重定向
  4. STM32 基础系列教程 32 – Ethnet+Lwip
  5. // D:\SaveLog\_SaveLog.dpr立即备份晓亮的电脑操作记录热键(快捷键) F11由于原来的 AutoIt 杀毒软件总是误报没办法只好麻烦一点用 Delphi XE4 做了...
  6. php 增加mysql 索引,【PHP】为什么 MySQL 添加索引后就可以提高查询速度
  7. RabbitMQ学习之messageconver插件实现(Gson)
  8. android功耗(23)---gps定位开发省电要点
  9. PHP学习笔记:利用百度api实现手机归属地查询
  10. Spring四个核心包
  11. 图片放大不清晰怎么办?
  12. 选择部门-选择员工(js)
  13. 植被覆盖指数计算教程(ENVI)
  14. 仿写“跳一跳”微信小游戏
  15. 算法学习 | 期望dp+概率dp
  16. 安全管理体系升级 迈动互联获得ISO国际认证
  17. 运维就是一场没有硝烟的战争
  18. iPhone13或许会支持25w快充
  19. Spark SQL架构工作原理及流程解析
  20. Bilibili到底有多少御坂妹?(三)

热门文章

  1. JavaScript基础(二)-类
  2. Netty与传统Server对比
  3. 结构体全局变量成员赋值
  4. asp.net mvc 生成二维码
  5. 蓝牙 MultipeerConnectivity
  6. 没有钱,能做什么呢?(转载)
  7. 【Java】Springboot项目中Transactional的使用方式
  8. 【Java】Springboot项目中jar包加密
  9. 测试用例-写测试用例时怎么入手
  10. pytest测试框架(二)---fixture介绍