前言
最近一直在对QComboBox的模型和视图委托进行了一些深入的研究,因此在这里做一个记录,总结一下。前两篇是对QCombobox的下拉表格的说明,以及对自定义委托和排序的讲解。本篇是对QComboBox的委托样式进行一些说明,然后做一个类似于QQ登录时的下拉框,会显示历史登录的账号头像等信息。
提示:以下是本篇文章正文内容,下面案例可供参考
一、子类化QAbstractListModel
由于是列表模型,因此选择QAbstractListModel进行子类化,重新实现。首先是data()和rowcount(),columnCount()不需要,因为是list模型内部有默认实现,原型如下:
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const = 0
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const = 0
我们不需要提供编辑功能,因此setData()不需要重新实现,只要重新实现上面两个函数即可。下面是我的代码:
头文件:
#ifndef Q_LISTMODEL_H
#define Q_LISTMODEL_H
#include <QAbstractListModel>
#include <QObject>
#include "__global.h"
class QListmodel : public QAbstractListModel
{
Q_OBJECT
public:
explicit QListmodel(QObject *parent = 0);
~QListmodel();
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
int rowCount(const QModelIndex &parent = QModelIndex()) const;
void setModelData(const QList<UserInfo>& );
private:
QList<UserInfo> InfoList;
};
#endif // Q_LISTMODEL_H
cpp文件:
#include "q_listmodel.h"
QListmodel::QListmodel(QObject *parent)
{
}
QListmodel::~QListmodel()
{
}
QVariant QListmodel::data(const QModelIndex &index, int role) const
{
if(Qt::DisplayRole == role){
return InfoList.at(index.row()).name;
}else if(Qt::DecorationRole == role){
return InfoList.at(index.row()).icon;
}else if(Qt::UserRole == role){
return InfoList.at(index.row()).number;
}else if(Qt::UserRole+1 == role){
return InfoList.at(index.row()).isonline;
}
return QVariant();
}
int QListmodel::rowCount(const QModelIndex &parent) const
{
return InfoList.size();
}
void QListmodel::setModelData(const QList<UserInfo> &data)
{
if(!InfoList.isEmpty())
InfoList.clear();
InfoList = data;
}
其中setModelData函数是由外部调用,设置模型数据,UserInfo是自定义的一个结构。定义在__global.h文件中,如下:
__global.h文件:
#ifndef __GLOBAL_H
#define __GLOBAL_H
#include <QIcon>
class QString;
typedef struct infomation{
QString name;
QString number;
QIcon icon;
bool isonline;
}UserInfo;
#endif // __GLOBAL_H
注:其中name是用户名,number是号码,icon是头像,isonline为是否在线
二、子类化QStyledItemDelegate
QStyledItemDelegate是QAbstractItemDelegate的子类,由QAbstractItemDelegate派生出来有两个类,一个是QItemDelegate,另一个就是QStyledItemDelegate。
QStyledItemDelegate类为模型中的数据项提供显示和编辑功能。 而QItemDelegate可用于为基于QAbstractItemView子类的项目视图提供自定义显示功能和编辑器小部件。二者大同小异,二者的区别在于绘制和向视图提供编辑器的方式,默认的是QStyledItemDelegate,QStyledItemDelegate使用当前样式绘制,并且能够使用 Qt Style Sheet
代码如下(示例):
头文件:
#ifndef COMBOBOXDELEGATE_H
#define COMBOBOXDELEGATE_H
#include <QObject>
#include <QStyledItemDelegate>
#include <QModelIndex>
#include <QStandardItemModel>
#include <QPainter>
#include <QLineEdit>
#include <QComboBox>
#include <QDebug>
class comboboxdelegate : public QStyledItemDelegate
{
Q_OBJECT
public:
explicit comboboxdelegate(QObject *parent = 0);
~comboboxdelegate();
void paint(QPainter * painter,const QStyleOptionViewItem & option,const QModelIndex & index) const;
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
private:
qreal radius = 8;
};
#endif // COMBOBOXDELEGATE_H
CPP文件如下:
#include "comboboxdelegate.h"
comboboxdelegate::comboboxdelegate(QObject *parent)
{
}
comboboxdelegate::~comboboxdelegate()
{
}
void comboboxdelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.isValid())
{
painter->save();
QString name = index.data(Qt::DisplayRole).toString();
QVariant icondata = index.data(Qt::DecorationRole);
QIcon icon = icondata.value<QIcon>();
QString number = index.data(Qt::UserRole).toString();
bool isonline = index.data(Qt::UserRole+1).toBool();
qDebug()<<name << number << isonline;
QRectF rect;
rect.setX(option.rect.x());
rect.setY(option.rect.y());
rect.setWidth( option.rect.width()-1);
rect.setHeight(option.rect.height()-1);
QPainterPath path;
path.moveTo(rect.topRight() - QPointF(radius, 0));
path.lineTo(rect.topLeft() + QPointF(radius, 0));
path.quadTo(rect.topLeft(), rect.topLeft() + QPointF(0, radius));
path.lineTo(rect.bottomLeft() + QPointF(0, -radius));
path.quadTo(rect.bottomLeft(), rect.bottomLeft() + QPointF(radius, 0));
path.lineTo(rect.bottomRight() - QPointF(radius, 0));
path.quadTo(rect.bottomRight(), rect.bottomRight() + QPointF(0, -radius));
path.lineTo(rect.topRight() + QPointF(0, radius));
path.quadTo(rect.topRight(), rect.topRight() + QPointF(-radius, -0));
if(option.state.testFlag(QStyle::State_Selected))
{
painter->setPen(QPen(Qt::blue));
painter->setBrush(QColor(0,255,127));
painter->drawPath(path);
}
else if(option.state.testFlag(QStyle::State_Raised))
{
painter->setPen(QPen(Qt::green));
painter->setBrush(QColor(0,127,255));
painter->drawPath(path);
}
else{
painter->setPen(QPen(Qt::gray));
painter->setBrush(QColor(255,255,255));
painter->drawPath(path);
}
QRect iconRect = QRect(rect.left()+3,rect.top()+3,30,30);
QRect nameRect = QRect(iconRect.right()+5, rect.top()+3, rect.width()-80, 20);
QRect circle = QRect(nameRect.right()+5,nameRect.top(),10,10);
QRect numberRect = QRect(nameRect.x(),nameRect.y()+20,100,20);
qDebug()<<iconRect<<nameRect<<circle<<numberRect;
painter->drawEllipse(circle);
painter->setPen(QPen(QColor(0,0,0)));
painter->setFont(QFont("微软雅黑", 9, QFont::Bold));
painter->drawText(nameRect,Qt::AlignLeft,name);
painter->drawText(numberRect,Qt::AlignLeft,number);
painter->drawPixmap(iconRect,icon.pixmap(iconRect.size()));
painter->restore();
}else{
qDebug()<<"index is vaild?";
}
}
QSize comboboxdelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
{
Q_UNUSED(option)
Q_UNUSED(index)
return QSize(200,40);
}
三、使用
mainwindow.h:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QDebug>
#include <QStringListModel>
#include "comboboxdelegate.h"
#include "q_listmodel.h"
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
private:
Ui::MainWindow *ui;
QListmodel *mListModel;
comboboxdelegate* m_delegate;
private:
void initmodel();
void setModelData();
};
#endif // MAINWINDOW_H
mainwindow.cpp:
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "__global.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
{
ui->setupUi(this);
initmodel();
ui->comboBox->setCurrentIndex(0);
}
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::initmodel()
{
mListModel = new QListmodel();
m_delegate = new comboboxdelegate(this);
ui->comboBox->setModel(mListModel);//设置模型
ui->comboBox->setItemDelegate(m_delegate);//设置委托
setModelData();
}
void MainWindow::setModelData()
{
QList<UserInfo> InfoList;
UserInfo info;
info.icon = QIcon(":/img/1.ico");
info.isonline = true;
info.name = "张三";
info.number = "0123456789";
InfoList.append(info);
UserInfo info1;
info1.icon = QIcon(":/img/2.ico");
info1.isonline = true;
info1.name = "李四";
info1.number = "44564664521";
InfoList.append(info1);
UserInfo info2;
info2.icon = QIcon(":/img/3.ico");
info2.isonline = true;
info2.name = "王二";
info2.number = "9876543210";
InfoList.append(info2);
mListModel->setModelData(InfoList);
}
我这边就简单的随便写几个数据做一下演示了,如果需要动态插入,移除模型的项,需要上述一QAbstractListModel子类化重写insertRows() 和 removeRows()函数。我这边就不做演示了,功能已实现。
下面看下效果图:
如果还有关于QComboBox的其他需求,也可以查看我的另外另外博客:
QComboBox自定义下拉表格
QComboBox自定义委托和IP动态排序
本文demo下载链接:dowmload
总结
以上就是今天要讲的内容,比较简单,文中如有错误或者不妥的地方,欢迎各位指出,一起学习进步。
如需转载,请注明出处。