实现自定义委托

委托(delegate) 用来渲染和编辑视图中不同的项。在大多数情况下,视图中默认的委托已经足够了。如果想更好地控制有关项的显示,通常可以通过使用自定义模型很简单地实现我们所想要的:在 data() 重新实现中,我们可以处理Qt::FontRole、Qt:: TextAlignmentRole、Qt::TextColorRole、Qt::BackgroundColorRole,并且它们会被默认的委托使用。例如,在之前所显示的城市和汇率例子
中,我们已经为了得到向右对齐的数字的效果处理了Qt::TextAlignmentRole。

Track Editor

如果想得到更多的控制,则可以创建自己的委托类并且把它设置在我们想要使用它的视图中。下面显示的音轨编辑器对话框就使用了一个自定义委托,它显示了音轨的标题和持续时间。模型中保存的数据是非常简单的 QString(标题)和 int(秒),但是持续时间将会被分隔成分钟和秒两部分,并且会通过 QTimeEdit 来让它变得可以编辑。

音轨编辑器对话框使用了一个 QTableWidget,这是一个可以在 QTableWidgetItem 上操作的方便的项视图子类。

TrackEditor.h

#ifndef TRACKEDITOR_H
#define TRACKEDITOR_H#include <QDialog>
#include <QList>class QDialogButtonBox;
class QTableWidget;class Track
{public:Track(const QString &title = "", int duration = 0);QString title;int duration;
};class TrackEditor : public QDialog
{Q_OBJECTpublic:TrackEditor(QList<Track> *tracks, QWidget *parent = 0);void done(int result);private slots:void addTrack();private:QTableWidget *tableWidget;QDialogButtonBox *buttonBox;QList<Track> *tracks;
};#endif

提供的数据是一个Track列表。

TrackEditor.cpp

#include <QtGui>#include "trackdelegate.h"
#include "trackeditor.h"Track::Track(const QString &title, int duration)
{this->title = title;this->duration = duration;
}TrackEditor::TrackEditor(QList<Track> *tracks, QWidget *parent): QDialog(parent)
{this->tracks = tracks;tableWidget = new QTableWidget(tracks->count(), 2);tableWidget->setItemDelegate(new TrackDelegate(1));tableWidget->setHorizontalHeaderLabels(QStringList() << tr("Track") << tr("Duration"));for (int row = 0; row < tracks->count(); ++row) {Track track = tracks->at(row);QTableWidgetItem *item0 = new QTableWidgetItem(track.title);tableWidget->setItem(row, 0, item0);QTableWidgetItem *item1= new QTableWidgetItem(QString::number(track.duration));item1->setTextAlignment(Qt::AlignRight);tableWidget->setItem(row, 1, item1);}tableWidget->resizeColumnToContents(0);buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok| QDialogButtonBox::Cancel);QPushButton *addTrackButton = buttonBox->addButton(tr("&Add Track"),QDialogButtonBox::ActionRole);connect(addTrackButton, SIGNAL(clicked()), this, SLOT(addTrack()));connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));QVBoxLayout *mainLayout = new QVBoxLayout;mainLayout->addWidget(tableWidget);mainLayout->addWidget(buttonBox);setLayout(mainLayout);setWindowTitle(tr("Track Editor"));
}void TrackEditor::done(int result)
{if (result == QDialog::Accepted) {tracks->clear();for (int row = 0; row < tableWidget->rowCount(); ++row) {QString title = tableWidget->item(row, 0)->text();QTableWidgetItem *item = tableWidget->item(row, 1);int duration = item ? item->text().toInt() : 0;tracks->append(Track(title, duration));}}QDialog::done(result);
}void TrackEditor::addTrack()
{tableWidget->insertRow(tableWidget->rowCount());
}

TraskEditor()
这个构造函数创建于一个表窗口部件,并没有简单地使用默认的委托,而是设置了自定义的TrackDelegate,传递保存时间数据的列作为参数。我们由设置列的表头开始,然后遍历数据,利用每一个音轨的名称和持续时间组装各行。

TrackDelegate.h

#ifndef TRACKDELEGATE_H
#define TRACKDELEGATE_H#include <QItemDelegate>class TrackDelegate : public QItemDelegate
{Q_OBJECTpublic:TrackDelegate(int durationColumn, QObject *parent = 0);void paint(QPainter *painter, const QStyleOptionViewItem &option,const QModelIndex &index) const;QWidget *createEditor(QWidget *parent,const QStyleOptionViewItem &option,const QModelIndex &index) const;void setEditorData(QWidget *editor, const QModelIndex &index) const;void setModelData(QWidget *editor, QAbstractItemModel *model,const QModelIndex &index) const;private slots:void commitAndCloseEditor();private:int durationColumn;
};#endif

我们使用 QltemDelegate 作为基类,所以可以从默认的委托实现中获益。如果想从头开始做,则可以使用 AbstractItemDelegate 作为基类。为了提供一个可以编辑数据的委托必须实现 createEditor()、setEditorData()和 setModelData()。还要实现 paint(),它用于改变持续时间这一列的显示。

TrackDelegate.cpp

#include <QtGui>#include "trackdelegate.h"TrackDelegate::TrackDelegate(int durationColumn, QObject *parent): QItemDelegate(parent)
{this->durationColumn = durationColumn;
}void TrackDelegate::paint(QPainter *painter,const QStyleOptionViewItem &option,const QModelIndex &index) const
{if (index.column() == durationColumn) {int secs = index.model()->data(index, Qt::DisplayRole).toInt();QString text = QString("%1:%2").arg(secs / 60, 2, 10, QChar('0')).arg(secs % 60, 2, 10, QChar('0'));QStyleOptionViewItem myOption = option;myOption.displayAlignment = Qt::AlignRight | Qt::AlignVCenter;drawDisplay(painter, myOption, myOption.rect, text);drawFocus(painter, myOption, myOption.rect);} else{QItemDelegate::paint(painter, option, index);}
}QWidget *TrackDelegate::createEditor(QWidget *parent,const QStyleOptionViewItem &option,const QModelIndex &index) const
{if (index.column() == durationColumn) {QTimeEdit *timeEdit = new QTimeEdit(parent);timeEdit->setDisplayFormat("mm:ss");connect(timeEdit, SIGNAL(editingFinished()),this, SLOT(commitAndCloseEditor()));return timeEdit;} else {return QItemDelegate::createEditor(parent, option, index);}
}void TrackDelegate::setEditorData(QWidget *editor,const QModelIndex &index) const
{if (index.column() == durationColumn) {int secs = index.model()->data(index, Qt::DisplayRole).toInt();QTimeEdit *timeEdit = qobject_cast<QTimeEdit *>(editor);timeEdit->setTime(QTime(0, secs / 60, secs % 60));} else {QItemDelegate::setEditorData(editor, index);}
}void TrackDelegate::setModelData(QWidget *editor,QAbstractItemModel *model,const QModelIndex &index) const
{if (index.column() == durationColumn) {QTimeEdit *timeEdit = qobject_cast<QTimeEdit *>(editor);QTime time = timeEdit->time();int secs = (time.minute() * 60) + time.second();model->setData(index, secs);} else {QItemDelegate::setModelData(editor, model, index);}
}void TrackDelegate::commitAndCloseEditor()
{QTimeEdit *editor = qobject_cast<QTimeEdit *>(sender());emit commitData(editor);emit closeEditor(editor);
}

TrackDelegate()
构造函数中的 durationColumn 参数告诉这个委托,哪一列保存的是音轨的持续时间。

paint()
因为我们想使用"分钟:秒"的格式显示持续时间,所以需要重新实现这个 paint()函数。两个arg() 调用中的参数分别为:要显示为字符串的整数、需要的字符串有多少个字符、整数的基数(10 代表十进制)和填充的字符。

为了右对齐文本,我们复制当前的风格选项并且覆盖默认的对齐方式。然后调用 QltemDelegate::drawDisplay()绘制这个文本,然后跟着的是 QltemDelegate::drawFocus(),如果当前项具有焦点,它就绘制一个焦点矩形,否则什么也不做。使用 drawDisplay()非常方便,特别是当使用了自定义的风格选项的时候。还可以使用绘图器直接绘制。

createEditor()
我们只想控制音轨持续时间的编辑,所以把音轨名称的编辑留给了默认的委托。这是通过检查要求委托提供一个编辑器的是哪一列实现这一点的。如果是持续时间所在的列,就创建一个QTimeEdit,设置正确的显示格式,并且把它的 editingFinished()信号和commitAndÇloseEditor()槽连接起来。对于其他任何一列,都把有关编辑的处理传递给默认的委托。

commitAndCloseEditor()
如果用户按下 Eriter 键或者把焦点移动到这个QTimeEdit 之外(但不是按下 Esc 键), editinggFinshed()信号就会被发射并且就会调用 commitAndCloseEditor()槽。这个槽会发射conmitData()信号,通知视图用被编辑的数据替换已经存在的数据。它还发射closeEditor()信号,通知视图已经不再需要这个编辑器了,这时模型将会把它删除。编辑器可以使用QObject::sender()获得,这个函数返回发射了触发这个槽的信号的对象。如果用户取消编辑(按下 Esc 键),视图将会简单地删除编辑器。

setEditorData()
当用户初始化编辑的时候,视图会调用 createEditor()创建一个编辑器,然后利用这个项的当前数据调用 setEditorData()来初始化编辑器。如果编辑器是用于持续时间列的,就按秒提取这个音轨的持续时间,并且设置 QTimeEdit 的时间为相应的分钟数和秒数;否则,就让默认的委托处理这个初始化。

setModelData()
如果用户完成了编辑(例如,在这个编辑器窗口部件外面按下鼠标左键,或者按下了 Enter或Esc 键) ,而不是取消编辑,模型就必须使用编辑器的数据进行更新。如果持续时间被编辑了,就从 QTimeEdit 中提取出分钟数和秒数,并且设置数据为相应的秒数。

main.cpp

#include <QApplication>#include "trackeditor.h"int main(int argc, char *argv[])
{QApplication app(argc, argv);QList<Track> tracks;tracks << Track("The Flying Dutchman: Overture", 630)<< Track("The Flying Dutchman: Wie aus der Fern laengst ""vergangner Zeiten", 374)<< Track("The Flying Dutchman: Steuermann, lass die Wacht",152)<< Track("Die Walkuere: Ride of the Valkyries", 286)<< Track("Tannhaeuser: Freudig begruessen wir die edle ""Halle", 384)<< Track("Tannhaeuser: Wie Todesahnung - O du mein holder ""Abendstern", 257)<< Track("Lohengrin: Treulich gefuert ziehet dahnin", 294)<< Track("Lohengrin: In fernem Land", 383)<< Track("Die Meistersinger von Nuernberg: Overture", 543)<< Track("Die Meistersinger von Nuernberg: Verachtet mir ""die Meister nicht", 200)<< Track("Die Meistersinger von Nuernberg: Ehrt eure ""deutschen Meister", 112)<< Track("Goetterdaemmerung: Funeral Music", 469)<< Track("Tristan und Isolde: Mild und leise, wie er ""laechelt", 375);TrackEditor editor(&tracks);editor.resize(600, 300);editor.show();return app.exec();
}

我们完全有可能创建一个可以很好地控制模型中任何一个项的编辑和显示的自定义委托,尽管在这种情况下不是必需的。我们已经选择控制特定的列,但是因为 QModelIndex 会被传递给重新实现的所有 QltemDelegate 的函数,所以可以按照行、列、矩形区域、父对象或者它们中的任意组合进行控制,如果需要还可以控制每一个单独的项。

Qt4_实现自定义委托相关推荐

  1. Qt自定义委托在QTableView中绘制控件、图片、文字

    自定义委托,继承于,QStyledItemDelegate类,重载Paint()函数, 1.实现在QTableView中绘制 格式字符串 2.实现在QTableView中绘制进度条 3.实现在QTab ...

  2. QT:在QTableView中使用各种自定义委托

    原文地址::https://blog.csdn.net/lhchen922/article/details/38367719 相关文章 1.QT:在QTableView中使用各种自定义委托----ht ...

  3. QTableView使用自定义委托(QItemDelegate)

    QTableView使用自定义委托(QItemDelegate) 需要在表格中绘制流程图,主要有箭头,方向,颜色,字符串,由于QTableView没有可用的绘制函数,所以需要自己去定义. 委托(del ...

  4. UE4/5多人游戏详解(七、自定义委托,实现寻找会话和加入会话的函数,通过Steam进行两台电脑的联机)

    目录 可能出现问题(在六部分的测试可能无法连接的问题[在末尾加上了,怕有人没看见在这里写一下]) 自定义委托 调整位置 创建更多的委托和回调函数给菜单: 多播和动态多播 代码: 委托变量 代码: 回调 ...

  5. C语言中的函数指针、函数的直接/间接调用、C# 委托(自定义委托、内置泛型委托、委托的实例化、委托的一般使用(模板方法、回调方法)、泛型委托、多播委托、同步/异步使用委托)

    文章目录 C语言中的函数指针 函数的直接调用与间接调用 Java中没有与委托对应的功能实体 C# 委托 C# 自定义委托类型 C# 内置泛型委托类型 委托的实例化 委托也支持泛型的使用 委托的一般使用 ...

  6. C#中在多个地方调用同一个触发器从而触发同一个自定义委托的事件

    场景 在Winfom中可以在页面上多个按钮或者右键的点击事件中触发同一个自定义的委托事件. 实现 在位置一按钮点击事件中触发 string parentPath = System.IO.Directo ...

  7. python tableview绑定字典_在QTableView中使用各种自定义委托

    思路: 1:为每一列定义委托: A:第一列是编号列,使用只读委托,令该列的单元格是只读的 B:第三列是ID列,只能输入1-12个数字,利用QLineEdit委托和正则表达式对输入进行限制 C:第四年龄 ...

  8. 自定义委托,事件,参数的简单随笔

    .Net Framework的编码规范: 委托类型的名称都应该以EventHandler结束. 委托的原型定义:有一个void返回值,并接受两个输入参数:一个Object 类型,一个 EventArg ...

  9. Qt4_实现自定义模型

    实现自定义模型 Qt的预定义模型为数据的处理和查看提供了很好的方法.但是,有些数据源不能有效地和预定义模型一起工作,这时就需要创建自定义模型,以方便对底层数据源进行优化. 在介绍如何创建自定义模型之前 ...

最新文章

  1. 正则匹配所有包括换行符
  2. 小白入门深度学习 | 第三篇:30分钟入门深度学习 - TensorFlow版
  3. php 某一天时间凌晨,PHP获得今天 天凌晨时间戳的例子
  4. 一个可以在github上搜代码段的网站
  5. 转载:【OpenCV入门教程之五】 分离颜色通道多通道图像混合
  6. Android--通知之Toast
  7. 职场有影帝出没,屌丝们请当心!
  8. 更换mysql_这些被你忽视的MySQL细节,可能会让你丢饭碗!
  9. java 获取注解_java 注解annotation的使用,以及反射如何获取注解
  10. 如何判断自己的手机是山寨机?如何判断山寨机的芯片型号和平台?
  11. 2016二级java题型分数_2016年英语六级考试题型、试卷结构及分值比例
  12. centos7 C++ 使用libjpeg-turbo (让jpg 转bmp以及bmp转jpg)
  13. qgg包(续)-小数据教程-数据分析
  14. java定义一个周长类三角形_point类 三点的三角形的周长、面积 编程求解矩形和圆面积 java 三角形的定义...
  15. ABAP tRFC和qRFC
  16. Spring AOP动态代理
  17. 【零信任落地案例】北京芯盾时代电信运营商零信任业务安全解决方案落地项目
  18. 批量安装当前文件夹下的exe文件
  19. LeetCode-Revers_Bits
  20. 利用计算机课堂导入的好处,小学语文课堂导入的作用和意义

热门文章

  1. Redis-数据结构02-简单动态字符串(sds)
  2. redis 支持 json_Spring Boot 中集成 Redis
  3. js map的get 和list比 那个快_js中let和var
  4. 攻防世界逆向——key
  5. Elasticsearch+elasticsearch-head的安装+Kibana环境搭建+ik分词器安装
  6. 字典的增删改查 daty 5
  7. Linux笔记(开机自动将kerne log保存到SD卡中)
  8. 【iCore4 双核心板_ARM】例程十一:DMA实验——存储器到存储器的传输
  9. LeetCode(1089)——复写零(JavaScript)
  10. Web存储—本地存储Cookie