方法一:使用自定义数据模型继承QAbstractTableModel
重载函数rowCount、columnCount、headerData、data、flags和setdata显示和编辑item对象。对enum Qt::ItemDataRole中角色的使用,可以控制一个item显示一个或者多个控件。常用的是DisplayRole和EditRole,有此两个角色可以把item当作编辑框使用。DecorateRole可以在项中添加图标,BackGroudRole和ForeGroudRole可以给背景色和字体上色,CheckStateRole可以给项添加一个QCheckBox控件。UserRole为自定义角色,当角色比较复杂时需要拓展角色,在UserRole+0/1…以上开始拓展。以上角色都是可以组合共存。可以实现如下表格效果:
上述方法有一个缺陷,item中只能使用提供的这几个默认控件,自定义控件或者其他的组合控件就没办法加载进item中,除非使用自定义代理。下面介绍自定义代理可以解决这个问题。
方法二:使用自定义代理继承QItemDelegate
重载paint、createEditor、setEditorData、setModelData、sizeHint、updateEditorGeometry、editorEvent。
Paint中绘制显示的组合控件的方法如下,如果不重写此paint,则显示的自定义控件都为空,只有点击时才会使用createEditor显示自定义控件:
//直接绘制
CIpCheckWidget *wdg = new CIpCheckWidget(NULL);
QPixmap pixmap(QSize(option.rect.width(), option.rect.height()));
wdg->render(&pixmap);
painter->drawPixmap(option.rect, pixmap);
//缓冲绘制
paintWidget(painter
,option.rect
,QString("%1-%2-%3-%4-%5,%6")
.arg(seleted)
.arg(wdg->data().str)
.arg(wdg->data().state)
.arg(wdg->data().pingState)
.arg(wdg->size().width())
.arg(wdg->size().height())
,wdg);
void CMyIPDelegate::paintWidget(QPainter* painter,const QRect& rect,const QString& catchKey,QWidget* w) const
{
QPixmap pixmap(QSize(rect.width(), rect.height()));
if(!QPixmapCache::find(catchKey,&pixmap))
{
w->render(&pixmap);
QPixmapCache::insert(catchKey,pixmap);
}
painter->drawPixmap(rect,pixmap);
}
//创建部件CreateEditor,主要返回QWidget指针,通过模型索引index设置QWidget部件数据
//SetEditorData通过index模型索引设置部件数据,可以在不调用CreateEditor时,刷新item数据
//SetModelData通过部件editor设置模型model索引index的数据
其中自定义部件的数据可能不是传统数据类型,复杂数据类型自定义结构需要注册后才能作为被QVariant识别,需调用Q_DECLARE_METATYPE方法声明为元数据类型如下:
struct SMyData
{
QString str;
Qt::CheckState state;
int pingState;
};
Q_DECLARE_METATYPE( SMyData)
但此方法经常会出现一个问题,每次点击编辑部件时,部件和原来图片的位置,发现会发生重叠加粗的现象,不能完全像方法一中默认委托创建出来的部件一样显示。使用updateEditorGeometry去调正效果不明显:
void CMyIPDelegate::updateEditorGeometry(QWidget *editor,
const QStyleOptionViewItem &option, const QModelIndex & index ) const
{
qDebug()<<"delegate::updateEditorGeometry";
editor->setGeometry(option.rect);
// dynamic_cast<CIpCheckWidget*>(editor)->setFixedSize(option.rect.width(), option.rect.height());
// dynamic_cast<CIpCheckWidget*>(editor)->move(option.rect.topLeft());
}
勾选不同item显示如下:
以上源码可参见https://github.com/ysj17366781/PortScan
除了以上QTableView,源码中还加入了获取本地网卡信息、设置本地网卡IP及ping表格中各个IP的功能。