会话列表基于QListView封装。
支持多种会话模式,根据所以类型不同支持自定义会话类别和自定义处理程序,比如您可以将一个自定义的消息ID传递过来,并在程序中设定目标ID的消息处理程序,那么在双击此会话时将自动打开处理程序进行处理。
除此之外支持大多数会话功能都支持,比如未读消息数量,最后一条消息内容,最后一条消息时间
支持列表模式和图标模式
注意:博客中的示例代码仅包含部分,完整代码视情况而定,目前暂不确定提供方式
根据管理先上图
自定义风格范围一如既往的广泛,具体请参考下面代码
/// 会话列表项风格委托样式数据结构
///
typedef struct LQSESSIONLIST_STYLE_{
double dAvatarsRadius = 0.5; //头像半径比例,如果为0则为矩形头像,最大不能大于0.5,当为0.5时头像显示圆形
QColor cItemHoverClrs = QColor(63,166,148); //鼠标悬停颜色
QColor cItemSelectClr = QColor(249,126,65); //选中项时颜色
QColor cIconHoverClrs = QColor(22,22,22,44); //鼠标悬停颜色
QColor cIconSelectClr = QColor(11,11,11,44); //选中项时颜色
QColor cItemNamesClrs = QColor(33,33,33); //会话名称文字颜色
QColor cNameHoverClrs = QColor(220,220,220); //会话文字鼠标悬停时颜色
QColor cNameSelectClr = QColor(255,255,255); //会话文字选中时颜色
QColor cItemMsglyClrs = QColor(66,66,66); //最后一条消息文字颜色
QColor cMsgHoversClrs = QColor(144,144,144); //最后一条消息文字鼠标悬停颜色
QColor cMsgSelectClrs = QColor(200,200,200); //最后一条消息文字选中颜色
QColor cUnreadMsgsBkg = QColor(245,65,91); //未读消息背景颜色
QColor cUnreadMsgText = QColor(255,255,255); //未读消息文字颜色
QColor cItemHeadLines = QColor(63,166,148,160);//头部线条颜色
QColor cItemSplitLine = QColor(63,166,148,66); //分割线颜色
QColor cLastTimerText = QColor(127,127,127); //会话时间颜色
QColor cDeviceBkgClrs = QColor(127,156,230); //设备背景颜色
//例如0个人消息,1群消息,3会议消息,4通知消息,5广告,具体情况可以自定义
QColor cGroupNodesClr = QColor(110,130,223); //群组会话节点标识背景色
QColor cUsersNodesClr = QColor(127,156,111); //用户会话节点标识背景色
QColor cNotifyNodeClr = QColor(253,139,28); //通知消息节点标识背景色
QColor cOtherNodesClr = QColor(127,127,127); //其他消息节点标识背景色
QColor cMeetingColors = QColor(151,95,203); //会议消息节点标识背景色
QColor cAdsNodeColors = QColor(77,77,77); //广告消息节点标识背景色
QColor cLiveNodeColor = QColor(247,74,90); //直播频道节点标识背景色
QColor cVipIconBkgClr = QColor(228,200,200,180); //会员图标背景颜色
QColor cVipNameColors = QColor(251,50,44); //会员名称颜色
QColor cVipMsgsColors = QColor(235,155,51); //会员消息颜色
QColor cVipNameHovers = QColor(252,75,40); //会员名称颜色
QColor cVipMsgsHovers = QColor(250,116,42); //会员消息颜色
QColor cVipNameSelect = QColor(240,59,85); //会员名称颜色
QColor cVipMsgsSelect = QColor(250,123,38); //会员消息颜色
QColor cAvatarFrmClrs = QColor(254,65,1); //头像高亮边框颜色
QColor cMouseHoverBkg = QColor(234,60,80); //鼠标移动时元素背景色
QColor cNodesHoverClr = QColor(148,152,228); //头部参考线节点鼠标悬停时颜色
QColor cNodeSelectClr = QColor(255,255,255); //头部参考线节点鼠标悬停时颜色
QColor cIgnoreBkgClrs = QColor(248,148,72); //忽略按钮背景颜色
QColor cIgnoreHoveClr = QColor(248,74,99); //忽略按钮悬停颜色
QColor cAvatarBkgClrs = QColor(66,66,66); //头像图像填充色
QColor cAnimateColors = QColor(44,44,44,44); //点击动画效果背景颜色
bool bRoundActiveBg = true; //选中背景是否绘制成半圆
uint uRoundActivPos = 1; //半圆背景位置,0左侧,1右侧
bool bShowHeadLines = true; //是否显示头部线条
bool bShowSplitLine = true; //是否显示分割线
bool bShowLastTimer = true; //是否显示会话时间
bool bShowDeviceInf = true; //是否显示设备信息
uint nSplitLineType = 2; //分割线样式,0实线,1虚线,2点线,3点划线,4双点划线
uint nHeadeLineType = 2; //标头参考线样式,0实线,1虚线,2点线,3点划线,4双点划线
bool bIconViewModel = false; //是否为列表视图,默认是
uint uItemHeightVal = 50; //行高
bool bHasShowGroups = false; //是否显示分组
uint uVipShowStyles = 2; //VIP显示风格,0不显示,1显示等级,2显示logo
uint uShowStatusIco = true; //是否在头像处显示联机状态
bool bShowIgnoreBtn = true; //是否显示忽略按钮
bool bGrayAvatarImg = true; //是否显示灰度头像
bool bArrayGroupIco = false; //是否使用群组多头像风格
bool operator==(const LQSESSIONLIST_STYLE_& rhs) // 操作运算符重载
{
return (dAvatarsRadius == rhs.dAvatarsRadius)
&& (cItemHoverClrs == rhs.cItemHoverClrs)
&& (cItemSelectClr == rhs.cItemSelectClr)
&& (cItemNamesClrs == rhs.cItemNamesClrs)
&& (cNameHoverClrs == rhs.cNameHoverClrs) //会话文字鼠标悬停时颜色
&& (cNameSelectClr == rhs.cNameSelectClr) //会话文字选中时颜色
&& (cItemMsglyClrs == rhs.cItemMsglyClrs)
&& (cMsgHoversClrs == rhs.cMsgHoversClrs) //最后一条消息文字鼠标悬停颜色
&& (cMsgSelectClrs == rhs.cMsgSelectClrs) //最后一条消息文字选中颜色
&& (cUnreadMsgsBkg == rhs.cUnreadMsgsBkg)
&& (cUnreadMsgText == rhs.cUnreadMsgText)
&& (cItemHeadLines == rhs.cItemHeadLines)
&& (cItemSplitLine == rhs.cItemSplitLine)
&& (cLastTimerText == rhs.cLastTimerText)
&& (cDeviceBkgClrs == rhs.cDeviceBkgClrs)
&& (cGroupNodesClr == rhs.cGroupNodesClr) //群组会话节点标识背景色
&& (cUsersNodesClr == rhs.cUsersNodesClr) //用户会话节点标识背景色
&& (cNotifyNodeClr == rhs.cNotifyNodeClr) //通知消息节点标识背景色
&& (cOtherNodesClr == rhs.cOtherNodesClr) //其他消息节点标识背景色
&& (cMeetingColors == rhs.cMeetingColors) //会议消息节点标识背景色
&& (cAdsNodeColors == rhs.cAdsNodeColors) //广告消息节点标识背景色
&& (cLiveNodeColor == rhs.cLiveNodeColor) //直播频道节点标识背景色
&& (cAvatarBkgClrs == rhs.cAvatarBkgClrs)
&& (bShowHeadLines == rhs.bShowHeadLines)
&& (bShowSplitLine == rhs.bShowSplitLine)
&& (bShowLastTimer == rhs.bShowLastTimer)
&& (bShowDeviceInf == rhs.bShowDeviceInf)
&& (nSplitLineType == rhs.nSplitLineType) //分割线样式,0实线,1虚线,2点线,3点划线,4双点划线
&& (nHeadeLineType == rhs.nHeadeLineType)
&& (bIconViewModel == rhs.bIconViewModel)
&& (uItemHeightVal == rhs.uItemHeightVal) //行高
&& (bHasShowGroups == rhs.bHasShowGroups) //是否显示分组
&& (uVipShowStyles == rhs.uVipShowStyles)
&& (bShowIgnoreBtn == rhs.bShowIgnoreBtn)
&& (bArrayGroupIco == rhs.bArrayGroupIco);
}
bool operator != (const LQSESSIONLIST_STYLE_& rhs) // 操作运算符重载
{
return !(*this == rhs);
}
}LQSESSIONLIST_STYLE,*PLQSESSIONLIST_STYLE;
委托绘制类主要定义如下
class LNCF_QTSOCIALLIBS_API Lncf_QSessionItemd : public Lncf_QListDelegate
{
Q_OBJECT
public:
Lncf_QSessionItemd(QObject *parent =nullptr);
~Lncf_QSessionItemd();
private:
/// 会话列表项风格委托样式数据结构变量
/// \brief tDelegateStyle
///
LQSESSIONLIST_STYLE tDelegateStyle;
QString sDevicePcIcons; //PC客户端图标
QString sDeviceMbIcons; //手机客户端图标
QString sDeviceWbIcons; //web客户端图标
QString sOtherAppIcons; //其它应用图标
QString sVipLogoImages; //会员图标
QString sSvipLogoImage; //超级会员图标
QString sOnlineImgLogo; //在线状态图标
QString sOffLineImages; //离线状态图标
QString sLeaveLogosImg; //离开状态图标
QString sBusyStatusImg; //忙碌状态图标
QString sStealthImages; //隐身状态图标
QString sNotDisturbImg; //勿扰状态图标
QString sCustomizeImgs; //自定义状态图标
QString sCallMeStatImg; //与我联系状态图标
QString sIgnoredImages; //忽略图标
QString sShieldBtnImgs; //屏蔽图标
QString sSourceAppsImg; //默认来源应用图标
QStringList sVipLogoImgLst; //会员等级图标列表
QStringList sSvipLogosList; //超级会员等级图标列表
uint uHeadLineWidth; //头部宽度
uint uIconGridWidth; //ICON视图格子宽度
uint uIconGridHeigh; //ICON视图格子高度
private:
/// 初始化会话列表委托
/// \brief InitSessionItemd
///
void InitSessionItemd();
private:
/// 重写系统绘制
void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
/// 绘制背景
/// \brief DrawBackgrounds
/// \param painter
/// \param option
/// \param rect
///
void DrawBackgrounds(QPainter *painter,const QStyleOptionViewItem &option, const QModelIndex &index) const;
/// 绘制会员等级图标
/// \brief DrawVipLevelImg
/// \param painter
/// \param option
/// \param bSvip
/// \param nVipLevel
/// \param bHover
/// \param sImage
///
void DrawVipLevelImg(QPainter *painter,const QStyleOptionViewItem &option,bool bSvip,int nVipLevel,bool bHover,std::u16string sImage) const;
/// 绘制会话来源名称
/// \brief DrawSessionName
/// \param painter
/// \param option
/// \param rect
/// \param sName
/// \param bRight
/// \param bVips
///
void DrawSessionName(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sName,bool bRight,bool bVips) const;
/// 绘制来源信息
/// \brief DrawSourcesInfo
/// \param painter
/// \param option
/// \param sName
/// \param sImage
///
void DrawSourcesInfo(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sName,std::u16string sImage,bool bRight) const;
/// 绘制最后一条消息内容
/// \brief DrawSessionMsgs
/// \param painter
/// \param option
/// \param rect
/// \param sMsg
/// \param bRight
/// \param bVips
/// \param bShield
///
void DrawSessionMsgs(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sMsg,bool bRight,bool bVips) const;
/// 绘制会话时间
/// \brief DrawSessionTime
/// \param painter
/// \param option
/// \param sDateTime
///
void DrawSessionTime(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sDateTime) const;
/// 绘制头像图片
/// \brief DrawAvatarImage
/// \param painter
/// \param option
/// \param sImagePath
/// \param uMsgType
/// \param bHover
/// \param uStatus
///
void DrawAvatarImage(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sImagePath,uint uMsgType,bool bHover,uint uStatus,uint uSex) const;
/// 绘制群组数组头像
/// \brief DrawGroupAvatar
/// \param painter
/// \param option
/// \param vImagePath
/// \param bHover
///
void DrawGroupAvatar(QPainter *painter,const QStyleOptionViewItem &option,QList<std::u16string> vImagePath,bool bHover) const;
/// 绘制头部线条
/// \brief DrawHeaderLines
/// \param painter
/// \param msgCount
/// \param sLastTime
/// \param nMsgType
/// \param bHover
/// \param uStatus
/// \param bShield
///
void DrawHeaderLines(QPainter *painter,const QStyleOptionViewItem &option,int msgCount,std::u16string sLastTime,int nMsgType,bool bHover,uint uStatus,bool bShield) const;
/// 绘制分割线
/// \brief DrawSplitupLine
/// \param painter
/// \param option
///
void DrawSplitupLine(QPainter *painter,const QStyleOptionViewItem &option) const;
/// 绘制未读消息计数
/// \brief DrawUnreadMsgly
/// \param painter
/// \param option
/// \param count
/// \param bHover
/// \param bShield
///
void DrawUnreadMsgly(QPainter *painter,const QStyleOptionViewItem &option,int count,bool bHover,bool bShield) const;
/// 绘制设备图标
/// \brief DrawDeviceImage
/// \param painter
/// \param option
/// \param nDeviceType
/// \param bHover
///
void DrawDeviceImage(QPainter *painter,const QStyleOptionViewItem &option,int nDeviceType,bool bHover) const;
/// 绘制屏蔽按钮
/// \brief DrawIgnoredBtns
/// \param painter
/// \param option
/// \param bHover
/// \param uMsgType
///
void DrawIgnoredBtns(QPainter *painter,const QStyleOptionViewItem &option,bool bHover,uint uMsgType) const;
private:
/// 获取默认头像路径
/// \brief GetDefaultAvatar
/// \param uSex
/// \param uMsgType
/// \return
///
QString GetDefaultAvatar(uint uSex,uint uMsgType) const;
/// 获取元素矩形区域
/// \brief GetElementRect
/// \param option
/// \param index,0:头像区域,1设备图标,2vip图标,3未读消息,4屏蔽按钮
/// \param nType
/// \return
///
QRect GetElementRect(const QStyleOptionViewItem &option,const QModelIndex &index,const int nType) const;
/// 重写视图项尺寸定义
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;
/// 重写视图项编辑事件
bool editorEvent(QEvent *event,QAbstractItemModel *model,const QStyleOptionViewItem &option,const QModelIndex &index) override;
/// 重写视图项辅助事件
bool helpEvent(QHelpEvent *event,QAbstractItemView *view,const QStyleOptionViewItem &option,const QModelIndex &index) override;
};
主要实现代码如下
/// 重写系统绘图
void Lncf_QSessionItemd::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
if(index.isValid())
{
painter->save();
painter->setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing);
QVariant var = index.data(LQSESSIONLIST_ROLES::SESSIONLIST_ITEMS);
LNCFQSESSION_VIEWDATAS ItemData = var.value<LNCFQSESSION_VIEWDATAS>();
// 绘制背景
this->DrawBackgrounds(painter,option,index);
bool bDrawVipLogo=tDelegateStyle.uVipShowStyles>0&&tDelegateStyle.uVipShowStyles<3&&(ItemData.uSvipLevelVals>0||(ItemData.uVipLevelValue>0&&ItemData.uVipLevelValue<11));
if(tDelegateStyle.bShowHeadLines&&!tDelegateStyle.bIconViewModel)
this->DrawHeaderLines(painter,option,ItemData.nUnreadMessage,ItemData.uLastlyMsgTime,ItemData.uSessionsTypes,index.data(LQSESSIONLIST_ROLES::ITEMSMSGNUM_HOVER).toBool(),ItemData.uOnlinesStatus,ItemData.bShieldSources);
// 绘制会话名称
this->DrawSessionName(painter,option,ItemData.uShowItemsName,!tDelegateStyle.bShowHeadLines?(ItemData.nUnreadMessage>0||tDelegateStyle.bShowLastTimer):false,bDrawVipLogo);
// 绘制最后一条会话消息
std::u16string uMsgContent=!ItemData.uLastlyMessage.empty()?ItemData.uLastlyMessage:ItemData.uItemsDescInfo;
if(!tDelegateStyle.bIconViewModel&&!ItemData.uLastlyMessage.empty())
this->DrawSessionMsgs(painter,option,ItemData.uLastlyMessage,!tDelegateStyle.bShowHeadLines?(ItemData.nUnreadMessage>0||tDelegateStyle.bShowLastTimer):false,bDrawVipLogo);
else{
if(!tDelegateStyle.bIconViewModel&&!ItemData.uSessionSource.empty())
this->DrawSourcesInfo(painter,option,ItemData.uSessionSource,ItemData.uSourcesImages,!tDelegateStyle.bShowHeadLines?(ItemData.nUnreadMessage>0||tDelegateStyle.bShowLastTimer):false);
else
this->DrawSessionMsgs(painter,option,ItemData.uItemsDescInfo,!tDelegateStyle.bShowHeadLines?(ItemData.nUnreadMessage>0||tDelegateStyle.bShowLastTimer):false,bDrawVipLogo);
}
// 绘制头像
bool bAvatarHover=index.data(LQSESSIONLIST_ROLES::ITEMAVATARS_HOVER).toBool()
&&!index.data(LQSESSIONLIST_ROLES::ITEMSDEVICE_HOVER).toBool()
&&!index.data(LQSESSIONLIST_ROLES::ITEMSVIPICO_HOVER).toBool()
&&!index.data(LQSESSIONLIST_ROLES::ITEMSMSGNUM_HOVER).toBool();
if(tDelegateStyle.bArrayGroupIco&&ItemData.uSessionsTypes==1)
this->DrawGroupAvatar(painter,option,ItemData.vAvatarImgPath,bAvatarHover);
else
this->DrawAvatarImage(painter,option,ItemData.uAvatarImgPath,ItemData.uSessionsTypes,bAvatarHover,ItemData.uSessionsTypes==0?ItemData.uOnlinesStatus:0,ItemData.uUserSexTypeId);
// 绘制VIP图标
if(bDrawVipLogo)
this->DrawVipLevelImg(painter,option,ItemData.uSvipLevelVals>0,
ItemData.uSvipLevelVals>0?ItemData.uSvipLevelVals:ItemData.uVipLevelValue,index.data(LQSESSIONLIST_ROLES::ITEMSVIPICO_HOVER).toBool(),
ItemData.uSvipLevelVals>0?ItemData.uSvipLevelsImg:ItemData.uVipLevalImage);
//绘制未读消息
if(!tDelegateStyle.bShowHeadLines||tDelegateStyle.bIconViewModel)
this->DrawUnreadMsgly(painter,option,ItemData.nUnreadMessage,index.data(LQSESSIONLIST_ROLES::ITEMSMSGNUM_HOVER).toBool(),ItemData.bShieldSources);
// 绘制会话时间
if(tDelegateStyle.bShowLastTimer&&(!tDelegateStyle.bShowHeadLines||tDelegateStyle.bIconViewModel))
this->DrawSessionTime(painter,option,ItemData.uLastlyMsgTime);
// 绘制设备图标
this->DrawDeviceImage(painter,option,ItemData.uDeviceTypeIds,index.data(LQSESSIONLIST_ROLES::ITEMSDEVICE_HOVER).toBool());
// 绘制忽略按钮
if((ItemData.uSessionsTypes==0||ItemData.uSessionsTypes==1)&&ItemData.nUnreadMessage>0&&!tDelegateStyle.bIconViewModel&&tDelegateStyle.bShowIgnoreBtn)
this->DrawIgnoredBtns(painter,option,index.data(LQSESSIONLIST_ROLES::ITEMSIGNORE_HOVER).toBool(),ItemData.uSessionsTypes);
// 绘制分割线
if(tDelegateStyle.bShowSplitLine&&!tDelegateStyle.bIconViewModel)
this->DrawSplitupLine(painter,option);
painter->restore();
}
}
/// 绘制背景
/// \brief Lncf_QSessionItemd::DrawBackgrounds
/// \param painter
/// \param option
/// \param rect
///
void Lncf_QSessionItemd::DrawBackgrounds(QPainter *painter,const QStyleOptionViewItem &option, const QModelIndex &index) const
{
painter->save();
if(this->bSeleceAnimate&&pItemsAnimated!=nullptr&&pItemsAnimated->pModelIndexObj == index&&!pItemsAnimated->bAnimeFinished){
QPainterPath path;
QRectF rect(0, 0, pItemsAnimated->qCurrentRadius, pItemsAnimated->qCurrentRadius);
rect.moveCenter(pItemsAnimated->pAnimeStartPos);
path.addEllipse(rect);
painter->save();
painter->setRenderHint(QPainter::Antialiasing);
painter->setClipRect(option.rect);
painter->fillPath(path, this->tDelegateStyle.cAnimateColors);
painter->restore();
}
else{
// 鼠标悬停或者选中时改变背景色
painter->setPen(Qt::NoPen);
bool bDarw = true;
if (option.state.testFlag(QStyle::State_MouseOver))
painter->setBrush(!tDelegateStyle.bIconViewModel?tDelegateStyle.cItemHoverClrs:tDelegateStyle.cIconHoverClrs);
if (option.state.testFlag(QStyle::State_Selected)) {
painter->setBrush(!tDelegateStyle.bIconViewModel?tDelegateStyle.cItemSelectClr:tDelegateStyle.cIconSelectClr);
if(tDelegateStyle.bRoundActiveBg&&!tDelegateStyle.bIconViewModel){
QRect rcBkg =option.rect;
rcBkg.setLeft(tDelegateStyle.uRoundActivPos==0?rcBkg.left()+rcBkg.height()/2-1:rcBkg.left());
rcBkg.setRight(tDelegateStyle.uRoundActivPos==1?rcBkg.right()-rcBkg.height()/2-1:rcBkg.right());
QRect rcRnd =QRect(tDelegateStyle.uRoundActivPos==0?option.rect.left():option.rect.right()-option.rect.height(),option.rect.top(),option.rect.height(),option.rect.height());
painter->drawPie(rcRnd,tDelegateStyle.uRoundActivPos==0?90.0*16:-90.0*16,180.0*16);
painter->drawRect(rcBkg);
bDarw = false;
}
}
if (option.state.testFlag(QStyle::State_Selected)&&option.state.testFlag(QStyle::State_MouseOver))
painter->setBrush(!tDelegateStyle.bIconViewModel?tDelegateStyle.cItemHoverClrs:tDelegateStyle.cIconHoverClrs);
if(!tDelegateStyle.bIconViewModel){
if(bDarw)painter->drawRect(option.rect);
}
else{
painter->drawRoundedRect(option.rect, 5, 5);
}
}
painter->restore();
}
/// 绘制会员等级图标
/// \brief DrawVipLevelImg
/// \param painter
/// \param option
/// \param bSvip
/// \param nVipLevel
/// \param bHover
///
void Lncf_QSessionItemd::DrawVipLevelImg(QPainter *painter,const QStyleOptionViewItem &option,bool bSvip,int nVipLevel,bool bHover,std::u16string sImage) const
{
if(nVipLevel>0&&nVipLevel<11){
painter->save();
QRectF vipRect,borderRect;
if(!tDelegateStyle.bIconViewModel){
int leftMargin=!tDelegateStyle.bShowHeadLines?option.rect.left()+this->tDelegateStyle.uItemHeightVal:option.rect.left()+this->tDelegateStyle.uItemHeightVal+uHeadLineWidth;
vipRect = QRect(leftMargin+1, option.rect.top()+6, 14, 14);
borderRect = QRect(leftMargin, option.rect.top()+5, 16, 16);
}
else{
vipRect = QRect(option.rect.left()+10, option.rect.top()+option.rect.width()-24, 14, 14);
borderRect = QRect(option.rect.left()+8, option.rect.top()+option.rect.width()-26, 18, 18);
}
painter->setPen(Qt::NoPen);
if(bHover&&this->bHasMouseEvent){
painter->setBrush(tDelegateStyle.bIconViewModel?tDelegateStyle.cMouseHoverBkg:tDelegateStyle.cAvatarFrmClrs);
painter->drawEllipse(borderRect);
}
else{
if(tDelegateStyle.bIconViewModel){
painter->setBrush(tDelegateStyle.cVipIconBkgClr);
painter->drawRoundedRect(borderRect, 9, 9);
}
}
QImage imgIcon;
//VIP显示风格,0不显示,1显示等级,2显示logo
switch (this->tDelegateStyle.uVipShowStyles) {
case 1:imgIcon=sImage.empty()?QImage(bSvip?sSvipLogosList[nVipLevel-1]:sVipLogoImgLst[nVipLevel-1]):QImage(QString::fromStdU16String(sImage));break;
case 2:imgIcon =bSvip?QImage(sVipLogoImages):QImage(sSvipLogoImage);break;
}
painter->drawImage(vipRect, imgIcon);
painter->restore();
}
}
/// 绘制会话来源名称
/// \brief Lncf_QSessionItemd::DrawSessionName
/// \param painter
/// \param option
/// \param rect
/// \param sName
/// \param bRight
/// \param bVips
///
void Lncf_QSessionItemd::DrawSessionName(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sName,bool bRight,bool bVips) const
{
painter->save();
QRectF nameRect;
if(!tDelegateStyle.bIconViewModel){
int vipWidth = 20;
int leftMargin=!tDelegateStyle.bShowHeadLines?(bVips?option.rect.left()+this->tDelegateStyle.uItemHeightVal+vipWidth:option.rect.left()+this->tDelegateStyle.uItemHeightVal):
(bVips?option.rect.left()+this->tDelegateStyle.uItemHeightVal+vipWidth+uHeadLineWidth:option.rect.left()+this->tDelegateStyle.uItemHeightVal+uHeadLineWidth);
int rightMargin =!tDelegateStyle.bShowHeadLines?(bRight?option.rect.width()-this->tDelegateStyle.uItemHeightVal-80:option.rect.width()-this->tDelegateStyle.uItemHeightVal-40):(bRight?option.rect.width()-this->tDelegateStyle.uItemHeightVal-80-uHeadLineWidth:option.rect.width()-this->tDelegateStyle.uItemHeightVal-40-uHeadLineWidth);
nameRect = QRect(leftMargin, option.rect.top()+5, rightMargin, 20);
}
else{
nameRect = QRect(option.rect.left()+2, option.rect.top()+option.rect.width(), option.rect.width()-4, 20);
}
// 鼠标悬停或者选中时改变背景色
painter->setPen(QPen(bVips?tDelegateStyle.cVipNameColors:tDelegateStyle.cItemNamesClrs));
if (option.state.testFlag(QStyle::State_MouseOver)) {
painter->setPen(Qt::NoPen);
painter->setBrush(tDelegateStyle.cItemHoverClrs);
if(tDelegateStyle.bIconViewModel)
painter->drawRoundedRect(nameRect, nameRect.height()/2, nameRect.height()/2);
painter->setPen(QPen(!bVips?tDelegateStyle.cNameHoverClrs:tDelegateStyle.cVipNameHovers));
}
if (option.state.testFlag(QStyle::State_Selected)) {
painter->setPen(Qt::NoPen);
painter->setBrush(tDelegateStyle.cItemSelectClr);
if(tDelegateStyle.bIconViewModel)
painter->drawRoundedRect(nameRect, nameRect.height()/2, nameRect.height()/2);
painter->setPen(QPen(!bVips?tDelegateStyle.cNameSelectClr:tDelegateStyle.cVipNameSelect));
}
QFont fontObj=painter->font();
fontObj.setPixelSize(nameRect.height()/(!tDelegateStyle.bIconViewModel?1.5:2));
QFontMetrics fontMetrics(fontObj);
painter->setFont(fontObj);
QString sShowName=fontMetrics.elidedText(QString::fromStdU16String(sName),Qt::ElideRight,nameRect.width());
painter->drawText(nameRect,!tDelegateStyle.bIconViewModel?(Qt::AlignLeft|Qt::AlignTop):Qt::AlignCenter,sShowName);
painter->restore();
}
/// 绘制来源信息
/// \brief DrawSourcesInfo
/// \param painter
/// \param option
/// \param sName
/// \param sImage
///
void Lncf_QSessionItemd::DrawSourcesInfo(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sName,std::u16string sImage,bool bRight) const
{
painter->save();
int leftMargin=!tDelegateStyle.bShowHeadLines?option.rect.left()+this->tDelegateStyle.uItemHeightVal:option.rect.left()+this->tDelegateStyle.uItemHeightVal+uHeadLineWidth;
int rightMargin=!tDelegateStyle.bShowHeadLines?(bRight?option.rect.width()-this->tDelegateStyle.uItemHeightVal-40:option.rect.width()-this->tDelegateStyle.uItemHeightVal):(bRight?option.rect.width()-this->tDelegateStyle.uItemHeightVal-40-uHeadLineWidth:option.rect.width()-this->tDelegateStyle.uItemHeightVal-uHeadLineWidth);
QRectF logoRect = QRect(leftMargin, option.rect.bottom()-23, 18, 18);
QRectF msgsRect = QRect(leftMargin+20, option.rect.bottom()-23, rightMargin, 18);
QImage imgIcon = sImage.empty()?QImage(sSourceAppsImg):QImage(QString::fromStdU16String(sImage));
if(imgIcon.isNull())
imgIcon = QImage(sSourceAppsImg);
painter->drawImage(logoRect, imgIcon);
painter->setPen(QPen(tDelegateStyle.cItemMsglyClrs));
if (option.state.testFlag(QStyle::State_MouseOver)) {
painter->setPen(QPen(tDelegateStyle.cMsgHoversClrs));
}
if (option.state.testFlag(QStyle::State_Selected)) {
painter->setPen(QPen(tDelegateStyle.cMsgSelectClrs));
}
QString sMsgText = tr("Session Source:");
if(sName.empty())
sMsgText = tr("Unknown session source");
else
sMsgText+=QString::fromStdU16String(sName);
QFont fontObj=painter->font();
fontObj.setPixelSize(msgsRect.height()/1.7);
QFontMetrics fontMetrics(fontObj);
painter->setFont(fontObj);
sMsgText=fontMetrics.elidedText(sMsgText,Qt::ElideRight,msgsRect.width());
painter->drawText(msgsRect,Qt::AlignLeft|Qt::AlignBottom, sMsgText);
painter->restore();
}
/// 绘制最后一条消息内容
/// \brief Lncf_QSessionItemd::DrawSessionMsgs
/// \param painter
/// \param option
/// \param rect
/// \param sMsg
///
void Lncf_QSessionItemd::DrawSessionMsgs(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sMsg,bool bRight,bool bVips) const
{
painter->save();
int leftMargin=!tDelegateStyle.bShowHeadLines?option.rect.left()+this->tDelegateStyle.uItemHeightVal:option.rect.left()+this->tDelegateStyle.uItemHeightVal+uHeadLineWidth;
int rightMargin=!tDelegateStyle.bShowHeadLines?(bRight?option.rect.width()-this->tDelegateStyle.uItemHeightVal-40:option.rect.width()-this->tDelegateStyle.uItemHeightVal):(bRight?option.rect.width()-this->tDelegateStyle.uItemHeightVal-40-uHeadLineWidth:option.rect.width()-this->tDelegateStyle.uItemHeightVal-uHeadLineWidth);
QRectF msgsRect = QRect(leftMargin, option.rect.bottom()-23, rightMargin, 18);
painter->setPen(QPen(bVips?tDelegateStyle.cVipMsgsColors:tDelegateStyle.cItemMsglyClrs));
if (option.state.testFlag(QStyle::State_MouseOver)) {
painter->setPen(QPen(!bVips?tDelegateStyle.cMsgHoversClrs:tDelegateStyle.cVipMsgsHovers));
}
if (option.state.testFlag(QStyle::State_Selected)) {
painter->setPen(QPen(!bVips?tDelegateStyle.cMsgSelectClrs:tDelegateStyle.cVipMsgsSelect));
}
QString sMsgText;
if(sMsg.empty())
sMsgText = tr("No message body available");
else
sMsgText=QString::fromStdU16String(sMsg);
QFont fontObj=painter->font();
fontObj.setPixelSize(msgsRect.height()/1.7);
QFontMetrics fontMetrics(fontObj);
painter->setFont(fontObj);
sMsgText=fontMetrics.elidedText(sMsgText,Qt::ElideRight,msgsRect.width());
painter->drawText(msgsRect,Qt::AlignLeft|Qt::AlignBottom, sMsgText);
painter->restore();
}
/// 绘制会话时间
/// \brief Lncf_QSessionItemd::DrawSessionTime
/// \param painter
/// \param option
/// \param sDateTime
///
void Lncf_QSessionItemd::DrawSessionTime(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sDateTime) const
{
painter->save();
QRectF timerRect;
if(!tDelegateStyle.bIconViewModel)
timerRect = QRect(option.rect.right()-78, option.rect.top()+6, 78, 16);
else timerRect = QRect(option.rect.left()+2, option.rect.top()+option.rect.width()+20, option.rect.width()-4, 16);
painter->setPen(tDelegateStyle.cLastTimerText);
QFont fontObj=painter->font();
fontObj.setPixelSize(timerRect.height()/2);
painter->setFont(fontObj);
painter->drawText(timerRect.x(),timerRect.y(),timerRect.width(),timerRect.height(),!tDelegateStyle.bIconViewModel?Qt::AlignRight:Qt::AlignCenter,QString::fromStdU16String(sDateTime));
painter->restore();
}
/// 绘制头像图片
/// \brief Lncf_QSessionItemd::DrawAvatarImage
/// \param painter
/// \param option
/// \param sImagePath
///
void Lncf_QSessionItemd::DrawAvatarImage(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sImagePath,uint uMsgType,bool bHover,uint uStatus,uint uSex) const
{
painter->save();
int leftMargin =0;
QRectF avatarRect,borderRect,stateRect,stateFrm;
if(!this->tDelegateStyle.bIconViewModel){
leftMargin=!tDelegateStyle.bShowHeadLines?option.rect.left()+5:option.rect.left()+5+uHeadLineWidth;
avatarRect = QRect(leftMargin, option.rect.top()+5, this->tDelegateStyle.uItemHeightVal-10, this->tDelegateStyle.uItemHeightVal-10);
borderRect = QRect(leftMargin-2, option.rect.top()+3, this->tDelegateStyle.uItemHeightVal-6, this->tDelegateStyle.uItemHeightVal-6);
stateRect = QRect(leftMargin+1, option.rect.top()+8,12,12);
stateFrm = QRect(leftMargin+1, option.rect.top()+8,12,12);
}
else{
borderRect = QRect(option.rect.left()+4, option.rect.top()+4, uIconGridWidth-8, uIconGridWidth-8);
avatarRect = QRect(option.rect.left()+8, option.rect.top()+8, uIconGridWidth-16, uIconGridWidth-16);
stateRect = QRect(option.rect.left()+9, option.rect.top()+10,12,12);
stateFrm = QRect(option.rect.left()+9, option.rect.top()+10,12,12);
}
if(tDelegateStyle.bIconViewModel){
painter->setPen(Qt::NoPen);
int nRadius=borderRect.height()*tDelegateStyle.dAvatarsRadius;
if (option.state.testFlag(QStyle::State_MouseOver)) {
painter->setBrush(tDelegateStyle.cItemHoverClrs);
painter->drawRoundedRect(borderRect,nRadius,nRadius);
}
if (option.state.testFlag(QStyle::State_Selected)) {
painter->setBrush(tDelegateStyle.cItemSelectClr);
painter->drawRoundedRect(borderRect,nRadius,nRadius);
}
}
else{
painter->setPen(Qt::NoPen);
int nRadius=borderRect.height()*tDelegateStyle.dAvatarsRadius;
if (option.state.testFlag(QStyle::State_Selected)) {
painter->setBrush(tDelegateStyle.cAvatarFrmClrs);
painter->drawRoundedRect(borderRect,nRadius,nRadius);
}
else{
if(bHover&&this->bHasMouseEvent){
painter->setBrush(tDelegateStyle.cMouseHoverBkg);
painter->drawRoundedRect(borderRect,nRadius,nRadius);
}
else{
painter->setBrush(Qt::transparent);
painter->drawRoundedRect(borderRect,nRadius,nRadius);
}
}
}
if(tDelegateStyle.dAvatarsRadius>0){
QPainterPath pathAvatar;
int nRadius=avatarRect.height()*tDelegateStyle.dAvatarsRadius;
pathAvatar.addRoundedRect(avatarRect , nRadius, nRadius);
painter->setClipPath(pathAvatar);
}
painter->setBrush(tDelegateStyle.cAvatarBkgClrs);
painter->drawRect(avatarRect);
QImage imgAvatar = QImage(QString::fromStdU16String(sImagePath));
if((uStatus==0||uStatus==5)&&uMsgType==0&&tDelegateStyle.bGrayAvatarImg)
imgAvatar = imgAvatar.convertToFormat(QImage::Format_Grayscale8,Qt::AutoColor);
if(imgAvatar.isNull())
imgAvatar = QImage(GetDefaultAvatar(uSex,uMsgType));
painter->drawImage(avatarRect, imgAvatar);
painter->restore();
if(uMsgType==0&&(tDelegateStyle.bIconViewModel||!tDelegateStyle.bShowHeadLines)&&tDelegateStyle.uShowStatusIco){
painter->save();
painter->setPen(Qt::NoPen);
if(uStatus!=0&&uStatus!=5){
painter->setBrush(tDelegateStyle.cUsersNodesClr);
painter->drawEllipse(stateFrm);
}
if(uStatus>0&&uStatus<8&&uStatus!=5){
///0脱机,1联机,2勿扰,3离开,4忙碌,5隐身,6自定义
switch (uStatus) {
case 0:painter->drawImage(stateRect, QImage(sOffLineImages));break;
case 1:painter->drawImage(stateRect, QImage(sOnlineImgLogo));break;
case 2:painter->drawImage(stateRect, QImage(sNotDisturbImg));break;
case 3:painter->drawImage(stateRect, QImage(sLeaveLogosImg));break;
case 4:painter->drawImage(stateRect, QImage(sBusyStatusImg));break;
case 5:painter->drawImage(stateRect, QImage(sOffLineImages));break;
case 6:painter->drawImage(stateRect, QImage(sCallMeStatImg));break;
case 7:painter->drawImage(stateRect, QImage(sCustomizeImgs));break;
}
}
painter->restore();
}
}
ListView的定义如下
class LNCF_QTSOCIALLIBS_API Lncf_QSessionListv : public Lncf_QtSocialListv
{
Q_OBJECT
Q_PROPERTY(QString sDevicePcIcons READ GetDevicePcIcons WRITE SetDevicePcIcons)
Q_PROPERTY(QString sDeviceMbIcons READ GetDeviceMbIcons WRITE SetDeviceMbIcons)
Q_PROPERTY(QString sDeviceWbIcons READ GetDeviceWbIcons WRITE SetDeviceWbIcons)
Q_PROPERTY(QString sVipLogoImages READ GetVipLogoImages WRITE SetVipLogoImages)
Q_PROPERTY(QStringList sVipLogoImgLst READ GetVipLogoImgLst WRITE SetVipLogoImgLst)
Q_PROPERTY(uint uHeadLineWidth READ GetHeadLineWidth WRITE SetHeadLineWidth)
Q_PROPERTY(uint uIdsFilterType READ GetIdsFilterType WRITE SetIdsFilterType)
Q_PROPERTY(bool bItemsMouseEvt READ GetItemsMouseEvt WRITE SetItemsMouseEvt)
Q_PROPERTY(bool bArrayGroupIco READ GetArrayGroupIco WRITE SetArrayGroupIco)
public:
explicit Lncf_QSessionListv(QWidget *parent = nullptr);
~ Lncf_QSessionListv();
protected:
/// 初始化列表虚函数
/// \brief InitSessionList
///
virtual void InitSessionList();
public:
/// 初始化封面布局,必须先调用此函数
/// \brief InitCoverLayout
/// \param btnList
/// \param bHorizeOption
/// \param sImgPath
/// \param sTitle
/// \param sLoadTip
/// \param sDesc
///
void InitCoversLayout(QList<LQCOVEROPTION_BNINF> btnList=QList<LQCOVEROPTION_BNINF>(),bool bHorizeOption = true,
std::u16string sImgPath= u"", std::u16string sTitle=u"",std::u16string sLoadTip=u"",std::u16string sDesc=u"") override;
private:
QStandardItemModel *pListItemModel = nullptr; //列表模型对象指针
Lncf_QSessionItemd *pItemsDelegate = nullptr; //列表项委托对象指针
Lncf_QSessionSortm *pSortFilteMode = nullptr; //列表筛选器模型对象指针
/// 数据查重类别
/// 0:全局视图项记录ID,GUID类型,关于自己使用的类型自行处理即可
/// 1:全局视图项记录ID,无符号长整形类型
/// 2:全局视图项记录ID,字符串类型类型
/// \brief uIdsFilterType
///
uint uIdsFilterType = 1;
/// 是否启用鼠标跟踪
/// \brief bMouseTracking
///
bool bMouseTracking = false;
public slots:
/// 设置列表项风格设置
/// \brief SetItemStyleVal
/// \param tagStyle
///
void SetItemStyleVal(const LQSESSIONLIST_STYLE &tagStyle);
/// 添加会话项目
/// \brief AddSessionItems
/// \param data :默认视图数据
/// \param appData :自定义app数据,此数据由app自行维护,默认情况下此数据不赋值
///
void AddSessionItems(LNCFQSESSION_VIEWDATAS data,QVariant appData = QVariant());
/// 设置会话列表数据集合
/// \brief SetSessionDatas
/// \param vList : 包含两条数据属性,1视图数据(LNCFQSESSION_VIEWDATAS),2应用自定义数据(QVariant)
///
void SetSessionDatas(std::vector<LNCFQSESSION_ITEMDATAS> &vList);
/// 会话数据是否存在
/// \brief HasSessionExist
/// \param data
/// \return
///
bool HasSessionExist(LNCFQSESSION_VIEWDATAS data);
/// 更新会话数据
/// \brief UptSessionDatas
/// \param data :默认视图数据
/// \param appData :自定义app数据,此数据由app自行维护,默认情况下此数据不赋值
///
void UptSessionDatas(LNCFQSESSION_VIEWDATAS data,QVariant appData = QVariant());
/// 根据模型索引更新模型数据
/// \brief UpdateItemsData
/// \param index :索引ID
/// \param data :视图数据
/// \param appData :App数据
///
void UpdateItemsData(const QModelIndex &index,LNCFQSESSION_VIEWDATAS data,QVariant appData = QVariant());
/// 设置目标索引的自定义app数据
/// \brief SetItemAppsData
/// \param index :模型索引ID
/// \param appData :应用数据,数据设置不会查重,而是直接替换原有数据[如果存在]。因此如果有必要请先获取然后在写入
///
void SetItemAppsData(const QModelIndex &index,QVariant appData = QVariant());
/// 删除指定索引的会话数据
/// \brief RemoveItemsData
/// \param index
/// \return
///
bool RemoveItemsData(const QModelIndex &index);
/// 设置指定索引会话消息显示名
/// \brief SetItemShowName
/// \param index
/// \param uName
///
void SetItemShowName(const QModelIndex &index,std::u16string uName);
/// 设置指定索引会话最后一条消息内容
/// \brief SetLastMessages
/// \param index
/// \param uMsg
///
void SetLastMessages(const QModelIndex &index,std::u16string uMsg);
/// 更新会话消息头像
/// \brief UpdateMsgAvatar
/// \param index
/// \param uImgPath
///
bool UpdateMsgAvatar(const QModelIndex &index,std::u16string uImgPath);
/// 删除会话
/// \brief DelSessionItems
/// \param index
///
void DelSessionItems(const QModelIndex &index);
//相关属性代码省略
};
使用需要连接的信号定义如下
/// 列表视图元素单击事件信号
/// \brief ViewElementClick
/// \param nElement 元素索引定义[0:头像,1设备图标,2vip图标,3未读消息,4屏蔽按钮]
/// \param index
///
void ViewElementClick(const int &nElement,const QModelIndex &index);
/// 列表视图元素双击事件信号
/// \brief ViewElementDbClick
/// \param nElement
/// \param index
///
void ViewElementDbClick(const int &nElement,const QModelIndex &index);
/// 列表视图Ui元素鼠标悬停事件
/// \brief ItemsElementHovers
/// \param nElement 元素索引定义[0:头像,1设备图标,2vip图标,3未读消息,4屏蔽按钮]
/// \param index
/// \param itemRect 当前项目矩形区域
/// \param evtPos 鼠标悬停位置坐标[当前窗口]
/// \param evtGlobalPos 鼠标悬停位置坐标[桌面窗口]
///
void ViewsElementHovers(const int &nElement,const QModelIndex &index,const QRect &itemRect,const QPoint &evtPos,const QPoint &evtGlobalPos);
/// 处理列表项单击信号
/// \brief HandItemsClicked
/// \param index
///
void ListItemsClicked(const QModelIndex &index);
篇幅太长,有关实现代码暂时不写了,如果后期有时间在补一部分重要代码