对应的博文为:

目录

Star Delegate Example

StarDelegate Class Definition

StarDelegate Class Implementation

StarEditor Class Definition

StarEditor Class Implementation

StarRating Class Definition

StarRating Class Implementation

The main() Function

Possible Extensions and Suggestions


Star Delegate Example

在QListView、QTableView、QTreeView这些控件里面如果要有个性化的item就得使用委托,委托在编辑item的时候让这些个性化的东西放置于最顶部。

这里告诉了一个道理当要自定义数据类型(比如int和QString混合,或者XX:xx这种数据)或者想定制渲染或者编辑存在的数据,就要子类化QAbstractItemDelegate或QItemDelegate(这两个的优劣我就不说了,看名字大家都知道了)。

Star Delegate Example 这个栗子就是来教我们怎么去渲染(我觉得这个应该叫渲染)和编辑一个打分的数据类型(就是用星星表示的)

这个栗子包含了3个类(官方文档就是清楚):
1.StarRating:自定义数据类型类,就是存那几个星星;
2.StarDelegate:继承于QItemDelegate,提供打分的功能,并且就是这个StarDelegate通过继承QItemDelegate实现数据类型(那几个星星)的处理;
3.StarEditor:继承于QWidget,也是被StarDelegate使用的,这吊玩意提供了让用户使用鼠标去编辑“星星”;

StarDelegate Class Definition

  class StarDelegate : public QStyledItemDelegate{Q_OBJECTpublic:StarDelegate(QWidget *parent = 0) : QStyledItemDelegate(parent) {}void paint(QPainter *painter, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;QSize sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const Q_DECL_OVERRIDE;void setEditorData(QWidget *editor, const QModelIndex &index) const Q_DECL_OVERRIDE;void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const Q_DECL_OVERRIDE;private slots:void commitAndCloseEditor();};

关键:重写了公有虚函数,实现了自定义渲染和编辑;

StarDelegate Class Implementation

首先是paint()函数,这个是父类的,目的是让视图重画item:

  void StarDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,const QModelIndex &index) const{if (index.data().canConvert<StarRating>()) {StarRating starRating = qvariant_cast<StarRating>(index.data());if (option.state & QStyle::State_Selected)painter->fillRect(option.rect, option.palette.highlight());starRating.paint(painter, option.rect, option.palette,StarRating::ReadOnly);} else {QStyledItemDelegate::paint(painter, option, index);}}

每一个item都会调用这个函数,通过使用model中的QModelIndex对象来表示(估计是可以表示到哪一行调用了这个函数),如果存储的数据类型就是那一坨星星,那就让他进行绘制(源码中可以看到一个if else,说的就是这个),否则使用QItemDelegate进行绘制。这样就确保了StarDelegate更加的灵活。

当item显示的是一坨星星时,选中item时会搞一个背景,然后通过使用StarRating::paint()来画item。

那一坨星星可以存到QVariant里面,这归功于Q_DECLARE_METATYPE()这个宏。

用户开始编辑一个Item的时候就会调用createEditor()

  QWidget *StarDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option,const QModelIndex &index) const{if (index.data().canConvert<StarRating>()) {StarEditor *editor = new StarEditor(parent);connect(editor, &StarEditor::editingFinished,this, &StarDelegate::commitAndCloseEditor);return editor;} else {return QStyledItemDelegate::createEditor(parent, option, index);}}

如果item里面放了那一坨星星,重写StartEditor这函数并且让editingFinished()信号与commitAndCloseEidtor()型号连接起来,目的是当关闭编辑功能后能更新模型。

关于commitAndCloseEdit()的代码!

  void StarDelegate::commitAndCloseEditor(){StarEditor *editor = qobject_cast<StarEditor *>(sender());emit commitData(editor);emit closeEditor(editor);}

当用户做完编辑时,就emit commitData()和closeEditor()(这两个信号都来源于QAbstractItemDelegate),这个是为了通知模型正在编辑数据并且通知视图不要让他编辑。

setEditorData()函数当要实现编辑功能的时候创建的,从模型中获取数据并且初始化他!

  void StarDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const{if (index.data().canConvert<StarRating>()) {StarRating starRating = qvariant_cast<StarRating>(index.data());StarEditor *starEditor = qobject_cast<StarEditor *>(editor);starEditor->setStarRating(starRating);} else {QStyledItemDelegate::setEditorData(editor, index);}}

此处源码里面编辑的时候调用了setStarRating()这函数!

当完成编辑的时候,就会调用setModelData()这个函数,作用是把editor中的数据给模型:

  void StarDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const{if (index.data().canConvert<StarRating>()) {StarEditor *starEditor = qobject_cast<StarEditor *>(editor);model->setData(index, QVariant::fromValue(starEditor->starRating()));} else {QStyledItemDelegate::setModelData(editor, model, index);}}

sizeHint()这个函数返回item的最合适的大小!

  QSize StarDelegate::sizeHint(const QStyleOptionViewItem &option,const QModelIndex &index) const{if (index.data().canConvert<StarRating>()) {StarRating starRating = qvariant_cast<StarRating>(index.data());return starRating.sizeHint();} else {return QStyledItemDelegate::sizeHint(option, index);}}

StarEditor Class Definition

StarDelegate类在实例化的时候要使用StarEditor,关于StartEditor代码如下:

  class StarEditor : public QWidget{Q_OBJECTpublic:StarEditor(QWidget *parent = 0);QSize sizeHint() const Q_DECL_OVERRIDE;void setStarRating(const StarRating &starRating) {myStarRating = starRating;}StarRating starRating() { return myStarRating; }signals:void editingFinished();protected:void paintEvent(QPaintEvent *event) Q_DECL_OVERRIDE;void mouseMoveEvent(QMouseEvent *event) Q_DECL_OVERRIDE;void mouseReleaseEvent(QMouseEvent *event) Q_DECL_OVERRIDE;private:int starAtPosition(int x);StarRating myStarRating;};

这个类通过移动鼠标让用户编辑那一坨星星数据,当鼠标单击一个item后会emiteditingFinished()的信号。

这个类从继承与QWidget,通过重写这些函数来重新实现mouse和paint的事件。startAtPosition()这个函数是一个辅助函数返回鼠标指向的星星的指针(就是指向那个坨星星的哪一个位置)

StarEditor Class Implementation

start的构造函数:

  StarEditor::StarEditor(QWidget *parent): QWidget(parent){setMouseTracking(true);setAutoFillBackground(true);}

通过setMouseTracking这个函数去启动鼠标追踪,即使用户没有点击鼠标,也能监听到鼠标。一般都开打QWidget自动填充的特性用于获取不透明的背景(如果不调用,视图的Editor就会干扰这个编辑器)

下面是关于paintEvent()函数

  void StarEditor::paintEvent(QPaintEvent *){QPainter painter(this);myStarRating.paint(&painter, rect(), this->palette(),StarRating::Editable);}

通过这个函数去画星星,这个函数就和StarDelegate差不多一毛一样。

  void StarEditor::mouseMoveEvent(QMouseEvent *event){int star = starAtPosition(event->x());if (star != myStarRating.starCount() && star != -1) {myStarRating.setStarCount(star);update();}}

在鼠标事件里面调用setStartCount(),通过使用成员myStarRating得到当前光标的位置,并且调用QWidget::update()去让他强制重绘。

  void StarEditor::mouseReleaseEvent(QMouseEvent * /* event */){emit editingFinished();}

当用户释放鼠标,就emit editingFinished()信号

  int StarEditor::starAtPosition(int x){int star = (x / (myStarRating.sizeHint().width()/ myStarRating.maxStarCount())) + 1;if (star <= 0 || star > myStarRating.maxStarCount())return -1;return star;}

startAtPosition这个函数使用了基础的线性代数去寻找当前光标对应那一坨星星中哪个星星的位置。

StarRating Class Definition

  class StarRating{public:enum EditMode { Editable, ReadOnly };explicit StarRating(int starCount = 1, int maxStarCount = 5);void paint(QPainter *painter, const QRect &rect,const QPalette &palette, EditMode mode) const;QSize sizeHint() const;int starCount() const { return myStarCount; }int maxStarCount() const { return myMaxStarCount; }void setStarCount(int starCount) { myStarCount = starCount; }void setMaxStarCount(int maxStarCount) { myMaxStarCount = maxStarCount; }private:QPolygonF starPolygon;QPolygonF diamondPolygon;int myStarCount;int myMaxStarCount;};Q_DECLARE_METATYPE(StarRating)

StarRating类代表了星星的等级(就是那一坨星星有几个组成),不仅如此他还提供了画那一坨星星的能力,这个是通过QPaintDevice实现的,这个一坨星星可以在view上画,或者在编辑器上画。myStarCount这个成员存储了当前有几个星星,myMaxStarCount存储了最多有多少个星星(存在QVariant这个神器里面)

通过Q_DECLARE_METATYPE()这个宏人QVariant知晓StarPating这个类,让QVariant能存储StarPating这个类。

StarRating Class Implementation

构造函数初始化了myStarCount和myMaxStarCount并且构造了一个多边形(就是星星)和钻石(非星星用这个代替)

  StarRating::StarRating(int starCount, int maxStarCount){myStarCount = starCount;myMaxStarCount = maxStarCount;starPolygon << QPointF(1.0, 0.5);for (int i = 1; i < 5; ++i)starPolygon << QPointF(0.5 + 0.5 * std::cos(0.8 * i * 3.14),0.5 + 0.5 * std::sin(0.8 * i * 3.14));diamondPolygon << QPointF(0.4, 0.5) << QPointF(0.5, 0.4)<< QPointF(0.6, 0.5) << QPointF(0.5, 0.6)<< QPointF(0.4, 0.5);}

paint()函数在StarRating这个对象的paint device上画了星星。

  void StarRating::paint(QPainter *painter, const QRect &rect,const QPalette &palette, EditMode mode) const{painter->save();painter->setRenderHint(QPainter::Antialiasing, true);painter->setPen(Qt::NoPen);if (mode == Editable) {painter->setBrush(palette.highlight());} else {painter->setBrush(palette.foreground());}int yOffset = (rect.height() - PaintingScaleFactor) / 2;painter->translate(rect.x(), rect.y() + yOffset);painter->scale(PaintingScaleFactor, PaintingScaleFactor);for (int i = 0; i < myMaxStarCount; ++i) {if (i < myStarCount) {painter->drawPolygon(starPolygon, Qt::WindingFill);} else if (mode == Editable) {painter->drawPolygon(diamondPolygon, Qt::WindingFill);}painter->translate(1.0, 0.0);}painter->restore();}

首先设置了一个画笔(pen)和画刷(brush这两个以后都用英文表示把,用中文太难过了)去画图。mode这个参数可以被设置成可编辑的或者可读的,如果是可编辑的就要用Highligh color去代替Foreground color,从而才能更好的画那一坨星星。

在编辑的时候,通过光标控制星星,没有星星的地方用小方块代替。

sizeHint()函数返回画出来的这坨星星最适合的大小:

  QSize StarRating::sizeHint() const{return PaintingScaleFactor * QSize(myMaxStarCount, 1);}

最大也只能画出myMaxStarCount这么多的星星。这个函数会被StarDelegate::sizeHint()与StartEditor::sizeHint()调用。

The main() Function

代码如下:

  int main(int argc, char *argv[]){QApplication app(argc, argv);QTableWidget tableWidget(4, 4);tableWidget.setItemDelegate(new StarDelegate);tableWidget.setEditTriggers(QAbstractItemView::DoubleClicked| QAbstractItemView::SelectedClicked);tableWidget.setSelectionBehavior(QAbstractItemView::SelectRows);QStringList headerLabels;headerLabels << "Title" << "Genre" << "Artist" << "Rating";tableWidget.setHorizontalHeaderLabels(headerLabels);populateTableWidget(&tableWidget);tableWidget.resizeColumnsToContents();tableWidget.resize(500, 300);tableWidget.show();return app.exec();}

主函数创建了一个QTableWidget和设置了StartDelegate,DoubleClicked和SelectedClicked已经设置好了编辑触发的功能,当星星等级的item被单击选中后,就会打开编辑功能。

populateTableWidget()这个函数填充了QTableWidget的数据

  void populateTableWidget(QTableWidget *tableWidget){static const struct {const char *title;const char *genre;const char *artist;int rating;} staticData[] = {{ "Mass in B-Minor", "Baroque", "J.S. Bach", 5 },...{ 0, 0, 0, 0 }};for (int row = 0; staticData[row].title != 0; ++row) {QTableWidgetItem *item0 = new QTableWidgetItem(staticData[row].title);QTableWidgetItem *item1 = new QTableWidgetItem(staticData[row].genre);QTableWidgetItem *item2 = new QTableWidgetItem(staticData[row].artist);QTableWidgetItem *item3 = new QTableWidgetItem;item3->setData(0,QVariant::fromValue(StarRating(staticData[row].rating)));tableWidget->setItem(row, 0, item0);tableWidget->setItem(row, 1, item1);tableWidget->setItem(row, 2, item2);tableWidget->setItem(row, 3, item3);}}

注意:使用qVariantFromValue把StarRating转化为QVariant

Possible Extensions and Suggestions

在Qt的视图模型框架里面有很多自定义方法,这个例子适合大多数自定义委托和编辑(我估计在国内18k内的Qt开发足够用了,18k外的可能要用别的),这个例子的星星委托和编辑没有尽可能做到以下几点:
1.使用编辑的方式,这种方式要调用QAbstractItemView::edit(),用这个代替编辑触发。这可以支持其他编译器的触发,比如QAbstractItemView::EditTrigger。举个例子,通过鼠标悬移动来改变数据这种效果比点击更好。
2.通过重写QAbstractItemDelegate::editorEvent(),这可以直接实现委托的编辑,而不是创建一个QWidget的子类来实现!

Qt官方文档阅读笔记-对官方Star Delegate Example实例的解析相关推荐

  1. Qt官方文档阅读笔记-QStyledItemDelegate Class描述

    对应的原文为: 笔记如下: 简单描述: QStyledItemDelegate提供了展示和编辑item的功能,让这两种功能更有个性化.QStyledItemDelegate是所有Item View的默 ...

  2. spring官方文档阅读笔记

    前言 几个月前阅读spring文档时做的笔记,记录了以写我认为重要的内容. IOC container IOC(Inverse of Control) 控制反转,也称为DI(Dependency In ...

  3. Flume官方文档阅读笔记及实际操作

    欢迎来到Apache Flume Flume是一个分布式的,高可靠的,高可用的,高性能的海量日志数据采集.聚合和传输的系统.它是基于数据流的简单的灵活的架构.它具有高鲁棒性并且有着可调节的可靠的故障恢 ...

  4. Ti 官方文档阅读笔记

    文章目录 参考资料 Optimizing TI mmWave Radar Configurations for FCC Certification Programming Chirp Paramete ...

  5. ZooKeeper官方文档学习笔记04-ZooKeeper的Java实例

    碎碎念:启动成功了一半.可以启动,可以debug,但是有些方法无法访问,而且create在哪里,我还不清楚.那个DataMonitor,不能完全按照官网写,要像我一样改一下,不然会报werror,因为 ...

  6. Javassist 官方文档 随手笔记

    Javassist 官方文档 随手笔记 Javassist.CtClass Class search path Introspection and customization \$0, \$1, \$ ...

  7. Open3D官方文档学习笔记

    Open3D官方文档学习笔记 第一部分--点云 1 可视化点云 2 体素降采样 3 顶点法线评估 4 访问顶点法线 补充:Numpy在Open3D中的应用 5 裁剪点云 补充1:获取点云坐标 补充2: ...

  8. ZooKeeper官方文档学习笔记03-程序员指南03

    我的每一篇这种正经文章,都是我努力克制玩心的成果,我可太难了,和自己做斗争. ZooKeeper官方文档学习笔记04-程序员指南03 绑定 Java绑定 客户端配置参数 C绑定 陷阱: 常见问题及故障 ...

  9. JMeter官方文档阅读及实践笔记(上)

    JMeter笔记 一.测试计划元件概览 本节简单介绍测试计划的不同部分. 最小测试将包括测试计划.线程组和一个或多个采样器. 1.Thread Group,线程组 线程组元素是任何测试计划的起点.所有 ...

最新文章

  1. webgl入门(2)-初识webgl和着色器
  2. IntelliJ IDEA快捷键学习
  3. java扫雷具有win7_Win7系统自带扫雷游戏打不开的解决方法
  4. bzoj2144: 跳跳棋(二分/倍增)
  5. 基于链路思想的SpringBoot单元测试快速写法
  6. ubuntu 安装dnsmasq dnscrypt-proxy
  7. 移动端rem单位用法
  8. katakana.php,片假名 平假名转换器 - Hi!Penpal!
  9. hp台式计算机u盘启动设置,惠普bios怎么设置u盘启动 惠普bios设置u盘启动方法
  10. teamviewer 服务器系统,远程支持服务器搭建teamviewer
  11. psql计算环比和同比
  12. Java中Base64的解析
  13. 静止、极轨卫星遥感图像太阳及卫星天顶、方位角的计算
  14. Android面试常见问题汇总
  15. js插件 excel在线编辑插件X-Spreadsheet
  16. 数字化门店管理|如何让门店数字化管理,更加贴合日常运营细节?
  17. 美团点评校招前端方向笔试题
  18. 自定义类型的深度剖析
  19. lssvm聚类研究(Matlab代码实现)
  20. 风吹雨名片互赞系统PHP程序

热门文章

  1. 什么才算是“真正的”编程能力?不提升这些能力,你何时能拿高薪!
  2. 在谈数据治理和数字化的时候,别忘了数据标准
  3. 我对C++内存分配方式的一点看法
  4. 对于公司,也是我对软件行业,软件项目的五想法
  5. 浅谈javascript数值类型转换
  6. php xmldom扩展,如何使用比根更深入的PHP DOM向XML添加新元素?
  7. transition属性详细讲解
  8. php算次方,php怎么计算几次方
  9. 日常生活开支记账明细_中小企业真的需要代理记账吗?
  10. python利用thinker制作多页面切换的桌面应用实例教程