发现问题的过程

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

  1. class CurrencyModel : public QAbstractTableModel
  2. {
  3. public:
  4. CurrencyModel(QObject *parent = 0);
  5. void setCurrencyMap(const QMap<QString, double> &map);
  6. int rowCount(const QModelIndex &parent) const;
  7. int columnCount(const QModelIndex &parent) const;
  8. QVariant data(const QModelIndex &index, int role) const;
  9. QVariant headerData(int section, Qt::Orientation orientation,
  10. int role) const;
  11. private:
  12. QString currencyAt(int offset) const;
  13. QMap<QString, double> currencyMap;
  14. };

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

  1. //返回一个项的任意角色的值,这个项被指定为QModelIndex
  2. QVariant MoReconQueue::data(const QModelIndex &index, int role) const
  3. {
  4. qDebug() <<"role:"<< role<< "index : " << index.row() << index.column();
  5. //模型索引无效,返回空值
  6. if (!index.isValid())
  7. return QVariant();
  8. //对其角色
  9. if (role == Qt::TextAlignmentRole)
  10. {
  11. return int(Qt::AlignRight | Qt::AlignVCenter);
  12. }
  13. //显示角色
  14. else if (role == Qt::DisplayRole)
  15. {
  16. return reconQueueAt(index.row(),index.column());
  17. }
  18. //返回空值
  19. return QVariant();
  20. }

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. (QColorQIcon 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);

}

}

最新文章

  1. 提额 APP
  2. 博客迁移到GitCafe
  3. jsoup简单的爬取网页数据
  4. 『摄影欣赏』16幅 Romantic 风格照片欣赏【组图】
  5. 5分钟理解iaas paas saas三种云服务区别
  6. 中文乱码问题(使用Servlet3.0新特性实现文件上传——上传文件名中文乱码问题)
  7. Jquery:强大的选择器&lt;一&gt;
  8. 1.Perl 多线程:Threads
  9. window.location.href 和 document.location.href
  10. spring mvc跨域(ajax post json)--filter方案
  11. java将一个List赋值给另一个List
  12. eclipse配置逆向工程
  13. [UE4]Switch on String,根据字符串决定条件分支,类似于高级语言中的switch语句
  14. Spark版本发布历史,及其各版本特性
  15. tomcat源码阅读之生命周期(LifeCycle)
  16. Jquery~跨域异步上传文件
  17. linux -- ubuntu桌面版安装xampp
  18. 前端小结(5)---- iframe
  19. Mybatis导入原生配置文件
  20. 2015.6.30 反弹的教训(想做T)

热门文章

  1. LeetCode 腾讯精选50题-- 买卖股票的最佳时机 II
  2. 关于小程序去除view/navigator 点击后默认阴影效果
  3. CSS设置元素的隐藏和显示
  4. Lab2 Report
  5. Spring Boot启动流程分析
  6. STM32工程模版
  7. 如何在Marketing Cloud里创建extension field扩展字段
  8. Failed to parse multipart servlet request; nested exception is java.io.IOException: The temporary upload location [/tmp/tomcat.1428942566812653608
  9. httpd安装mod_jk模块
  10. Mysql的mysqldump详解