C++ Qt开发社交好友列表【全是干货!】

1、申明:不是专业的Qt开发者,项目需要国产化系统场景,因此作者四个小时入门Qt,从此拉开了Qt的战场。

2,场景:在做支持国产化OS的社交软件时 考虑了很多UI框架,首先考虑的是Electron,其次是QML,然后是QWidget和GTK。经过详细的需求考量之后选择使用Qt作为GUi开发基础库。选择QWidget的原因包括以下几点:

a、资源占用合理,虽然相比较windows自带的GUI框架例如WIn32 SDKs和MFC以及和第三方的windows GUI库比如duilib soui等内存占用稍多,但相比较Electron相同的Ui只需要五分之一甚至十分之一的资源利用即可完成。比起QML和WPF也仅需三分之一的内存即可实现相同效果的UI。当然WPF不能跨平台。程序员口中的性能过剩在企事业单位中不存在,在4G内存的电脑上Electron等方案并不可行。

b、高性能,QWidget完全使用C++开发,因此一如既往的继承了C++的高性能特性,尤其是在低配置的计算机上,优势明显。但是由于QWidget使用CPU绘图,因此在高配置的电脑上除了节省资源,并不能体现出太大的Ui渲染优势。

c、使用C++开发,具备更底层的控制和灵活性。得益于C++的语言优势。Qt可以使用所有的C++第三方库,具备非常强的扩展和更高级的计算机使用权限,于此同时提供更加底层的设备访问功能和灵活的外部程序嵌入。由于使用C++开发,因此可以通过C风格导出风格封装 可作为插件提供用于其他语言跨语言调用。方便系统集成,这是高级语言无法做到的。

d、对计算机配置要求低。得益于C++的内存结构和执行原理,导致C++程序在资源利用上有着先天优势,相同的功能只需要高级语言内存的五分之一到十分之一即可完成。

e、跨平台,在完善的全方位跨平台的GUI框架选择上Qt似乎唯一而非之一,因此不再多说。

f、完善程度高,相比较GTK,Qt可以说是最佳的选择,无论从组件功能还是底层APi封装上都提供了相对完整的体验,没有技术断层。

g、支持高分屏,其实Qt在5之前高分屏支持很不理想,即便是在Qt中 5.14.2之前的版本都存在问题。在5.12之前只支持整倍缩放,在5.14.2时虽然支持了非整倍缩放,但是存在非整倍缩放时控件底部会存在一条绝对一像素的穿透。

注意:Qt的商业使用许可价格不便宜。


第一篇文章,前奏有点长,现在开始正文。

本文主题是使用QListView开发一个社交好友列表功能,功能丰富,支持非常丰富的属性功能,可以低代码实现各种风格的列表风格,比如微信,QQ,等主流社交软件的好友列表,包含但不限于以下功能

a.支持分组显示或不分组显示。

b.支持自定义分组和索引导航分组

c.支持头像的圆角比例

d.支持灰度头像

e.支持标头状态线

f.支持分割线

g.支持各种自定义颜色

h.支持使用文字头像或图像头像或图像不存在时是用文字头像

i.支持多种排序模式

j.支持vip和svip标识

k.支持列表和图标模式

l.支持自定义所有图标

m.支持选种样式风格

n.支持好友分组成员统计

o.支持鼠标单击,双击,悬停时触发Ui元素事件

p.支持右击时发送分组数据或好友数据信号

q.支持元素悬停效果

r.支持自定义选项按钮

s.支持鼠标移动上去之后显示选项按钮,包括自定义选项,语音通话,视频通话 等功能

PS:先上截图

gif模糊的没法看,那就一张一张来




图不多上,由于篇幅有限我们首先重点说明计数要点

1、分组,由于是ListView,因此主要靠Mode的setData的role区分分组和用户,分组展开和闭合是通过设置行隐藏和显示实现,在目标分组下存在一个与分组相同的data role,根据此role隐藏或显示row。由于这个实现没有自定义处理mode,因此在数据多的时候并不理想,但这不是重点。因此此列表视图建议好友数量不要超过一万。否则会影响体验。笔者测试数据为3万条

2、item元素事件,根据Rect区域判断item上的图标或按钮区域,所有按钮皆通过绘制模拟,并非button等类。

核心代码

1、样式风格结构体

/// 会话列表项风格委托样式数据结构

///

typedef struct LQFRIENDSLIST_STYLE_{

    QColor    cGroupBkgColor = QColor(88,88,88,44);  //分组背景色

    QColor    cGroupExpanClr = QColor(77,77,77,44);  //分组展开背景色

    QColor    cGroupHoverClr = QColor(254,118,19);    //分组鼠标悬停背景颜色

    QColor    cGroupExpHover = QColor(238,156,109);  //分组展开悬停背景色

    QColor    cGroupsBorders = QColor(117,131,218);  //分组边框颜色

    QColor    cItemsBkgColor = QColor(192,192,192,22);//好友背景色

    QColor    cItemsHoverClr = QColor(69,176,142);    //好友鼠标悬停背景色

    QColor    cItemSelectClr = QColor(244,123,64);    //好友选中背景色

    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    cGroupTxtColor = QColor(44,44,44);      //分组背景色

    QColor    cGroupHoverTxt = QColor(255,255,255);    //分组鼠标悬停背景颜色

    QColor    cGroupExpanTxt = QColor(33,33,33);      //分组鼠标悬停背景颜色

    QColor    cItemsTxtColor = QColor(33,33,33);      //好友文字颜色

    QColor    cItemsHoverTxt = QColor(255,255,255);    //好友鼠标悬停背景色

    QColor    cItemSelectTxt = QColor(235,235,235);    //好友选中背景色

    QColor    cGroupCountBkg = QColor(127,127,127);    //分组成员统计背景颜色

    QColor    cGroupCountTxt = QColor(220,220,220);    //分组成员统计文字颜色

    QColor    cGroupNodeClrs = QColor(127,127,127);    //分组节点图标颜色

    QColor    cGroupNodeBkgd = QColor(58,191,136);    //分组节点背景颜色

    QColor    cGroupNodesExp = QColor(114,133,218);    //分组节点展开背景颜色

    QColor    cDescHoverClrs = QColor(144,144,144);    //摘要文字鼠标悬停颜色

    QColor    cDescSelectClr = QColor(200,200,200);    //摘要文字选中颜色

    QColor    cItemHeadLines = QColor(63,166,148,160); //头部参考线颜色

    QColor    cItemSplitLine = QColor(63,166,148,66);  //分割线颜色

    QColor    cAvatarFrmClrs = QColor(250,74,33);      //头像边框颜色

    QColor    cMouseHoverBkg = QColor(124,144,218);    //鼠标悬停背景颜色

    QColor    cAvatarBkgClrs = QColor(55,55,55);      //头像背景填充颜色

    QColor    cUsersNodesClr = QColor(145,162,229);    //头像节点颜色

    QColor    cVipIconBkgClr = QColor(228,200,200,180);  //会员图标背景颜色

    QColor    cVipNameColors = QColor(251,50,44);    //会员名称颜色

    QColor    cVipDescColors = QColor(235,155,51);    //会员消息颜色

    QColor    cVipNameHovers = QColor(252,75,40);    //会员名称颜色

    QColor    cVipDescHovers = QColor(250,116,42);    //会员消息颜色

    QColor    cVipNameSelect = QColor(240,240,240);  //会员名称颜色

    QColor    cVipDescSelect = QColor(250,250,250);  //会员消息颜色

    QColor    cDeviceBkgClrs = QColor(127,156,230);  //设备背景颜色

    QColor    cOptionBkgClrs = QColor(248,148,72);    //选项按钮背景颜色

    QColor    cVideosBkgClrs = QColor(130,144,228);  //选项按钮悬停颜色

    QColor    cAudiosBkgClrs = QColor(71,186,152);    //选项按钮悬停颜色

    QColor    cOptionHoveClr = QColor(248,74,99);    //选项按钮悬停颜色

    bool      bRoundAvtiveBg = true;                  //选中背景是否绘制成半圆

    bool      bShowHeadLines = true;                  //是否显示头部线条

    bool      bShowSplitLine = 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;                    //行高

    uint      uItemMinHeight = 34;                    //小图标模式行高

    uint      uGroupsHeights = 26;                    //分组行高

    uint      uVipShowStyles = 1;                    //VIP显示风格,0不显示,1显示等级,2显示logo

    bool      uShowStatusIco = true;                  //是否在头像处显示联机状态

    uint      uHeadRectWidth = 40;                    //头部宽度

    uint      uIconGridWidth = 72;                    //ICON视图格子宽度

    uint      uIconGridHeigh = 100;                  //ICON视图格子高度

    uint      uGroupStyleIds = 0;                    //分组风格,0默认风格,1居中

    uint      uGroupBorderId = 0;                    //分组边框风格,0不显示边框,1全部边框,2上,3下

    float    fBordersWidths = 0.5;                  //边框宽度

    double    dGroupRadiusId = 0;                    //分组边框半径

    uint      uItemsStyleIds = 0;                    //列表项风格,0大图标模式,1小图标模式

    uint      uExpandGroupId = 1;                    //展开和闭合分组操作方式,0单击箭头,1单击整个分组项目,0双击简单,2双击整个分组项

    uint      uHorizeMarginG = 0;                    //分组项水平Margin

    uint      uVerticMarginG = 0;                    //分组项垂直Margin

    uint      uHorizeMarginU = 0;                    //用户项水平Margin

    uint      uVerticMarginU = 0;                    //用户项垂直Margin

    double    dAvatarsRadius = 0.5;                  //用户头像圆角半径

    bool      bShowUserCount = true;                  //是否显示分组成员统计

    bool      bIsShowSummary = true;                  //显示用户摘要,如果为false则表示显示来源

    bool      bShowOptionBtn = true;                  //显示选项按钮

    bool      bIsShowMoreBtn = true;                  //是否显示自定义处理按钮

    bool      bRandomAvbgClr = true;                  //在显示文字头像事是否使用随机背景颜色

    uint      bAvatarsStyles = 1;                    //头像显示风格索引,0仅显示图像,无头像图像时显示默认头像,1无图像时显示名称第一字符,2仅显示名称第一字符

    bool      bGrayAvatarImg = true;                  //是否启用头像灰度,启用后如果用户脱机则显示灰色头像

    bool operator==(const LQFRIENDSLIST_STYLE_& rhs) // 操作运算符重载

    {

      //省略篇幅已删减

    }

    bool operator != (const LQFRIENDSLIST_STYLE_& rhs) // !=操作运算符重载

    {

        return !(*this == rhs);

    }

}LQFRIENDSLIST_STYLE,*PLQFRIENDSLIST_STYLE;

 2、委托绘制类头文件部分代码

class LNCF_QTSOCIALLIBS_API Lncf_QFriendsItemd:public QStyledItemDelegate

{

    Q_OBJECT

public:

    explicit Lncf_QFriendsItemd(QObject *parent = nullptr);

    ~Lncf_QFriendsItemd();

private:

    /// 初始化好友列表委托

    /// \brief InitFriendsItemd

    ///

    void InitFriendsItemd();

protected:

    /// 好友列表项风格委托样式数据结构变量

    /// \brief tDelegateStyle

    ///

    LQFRIENDSLIST_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              sSourceAppsImg;  //默认来源应用图标

    QString              sGroupExpanImg;  //分组展开图标

    QString              sGroupCloseImg;  //分组关闭图标

    QString              sVideoChatImgs;  //视频会话图标

    QString              sAudioChatImgs;  //音频通话图标

    QString              sMoreOptionImg;  //更多选项图标

    QStringList          sVipLogoImgLst;  //会员等级图标列表

    QStringList          sSvipLogosList;  //超级会员等级图标列表

    QImage              pGroupExpanImg;  //分组展开图标对象

    QImage              pGroupCloseImg;  //分组收起图标对象

    bool                bHasMouseEvent;  //是否启用鼠标事件

    bool                bHasHoverEvent = false;  //是否处理鼠标悬停事件

    bool                bShowItemsTips = true;  //是否显示鼠标悬停时提示信息

    bool                bNavGroupStyle = false;  //是否为索引分组风格

protected:

    /// 重写创建编辑器

    QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,const QModelIndex &index) const override;

    /// 重写系统绘制

    virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;

    /// 绘制背景

    /// \brief DrawBackgrounds

    /// \param painter

    /// \param option

    /// \param bGroup

    /// \param bExpand

    ///

    virtual void DrawBackgrounds(QPainter *painter,const QStyleOptionViewItem &option,bool bGroup,bool bExpand) const;

    /// 绘制分组项

    /// \brief DrawItemsGroups

    /// \param painter

    /// \param option

    /// \param itemData

    ///

    virtual void DrawItemsGroups(QPainter *painter,const QStyleOptionViewItem &option,bool bExpand,LNCFQFRIENDS_LISTGROUP itemData,const QModelIndex &index) const;

    /// 绘制头部参考线

    /// \brief DrawItemsHeader

    /// \param painter

    /// \param option

    /// \param bGroup

    /// \param uStatus

    ///

    virtual void DrawItemsHeader(QPainter *painter,const QStyleOptionViewItem &option,bool bGroup,uint uStatus) const;

    /// 绘制头像

    /// \brief DrawItemsAavtar

    /// \param painter

    /// \param option

    /// \param sImagePath

    /// \param bHover

    /// \param uSex

    /// \param uStatus

    /// \param uDevice

    /// \param sName

    ///

    virtual void DrawItemsAavtar(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sImagePath,bool bHover,uint uSex,uint uStatus,std::u16string sName=u"") const;

    /// 绘制会员等级图标

    /// \brief DrawVipLevelImg

    /// \param painter

    /// \param option

    /// \param bSvip

    /// \param nVipLevel

    /// \param bHover

    /// \param sImage

    ///

    virtual void DrawVipLevelImg(QPainter *painter,const QStyleOptionViewItem &option,bool bSvip,int nVipLevel,bool bHover,std::u16string sImage) const;

    /// 绘制好友显示名

    /// \brief DrawDisplayName

    /// \param painter

    /// \param option

    /// \param sName

    ///

    virtual void DrawDisplayName(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sName,bool bVips) const;

    /// 绘制用户摘要信息

    /// \brief DrawUserSummary

    /// \param painter

    /// \param option

    /// \param sDesc

    /// \param bVips

    ///

    virtual void DrawUserSummary(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sDesc,bool bVips) const;

    /// 绘制来源信息

    /// \brief DrawSourcesInfo

    /// \param painter

    /// \param option

    /// \param sName

    /// \param sImage

    ///

    virtual void DrawSourcesInfo(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sName,std::u16string sImage,bool bVips) const;

    /// 绘制设备图标

    /// \brief DrawDeviceImage

    /// \param painter

    /// \param option

    /// \param nDeviceType

    /// \param bHover

    ///

    virtual void DrawDeviceImage(QPainter *painter,const QStyleOptionViewItem &option,int nDeviceType,bool bHover) const;

    /// 绘制选项图标

    /// \brief DrawOptionsBtns

    /// \param painter

    /// \param option

    /// \param uHover    :鼠标移动的控件索引,0无,1音频通话,2视频通话,3更多

    /// \param bAudio    :是否绘制音频通话快速按钮

    /// \param bVideo    :是否绘制视频通话快速按钮

    ///

    virtual void DrawOptionsBtns(QPainter *painter,const QStyleOptionViewItem &option,uint uHover,bool bAudio,bool bVideo) const;

    /// 绘制分割线

    /// \brief DrawSplitupLine

    /// \param painter

    /// \param option

    ///

    virtual void DrawSplitupLine(QPainter *painter,const QStyleOptionViewItem &option) const;

public:

    /// 获取视图项目风格数据结构

    /// \brief GetItemStyleData

    /// \return

    ///

    LQFRIENDSLIST_STYLE GetItemStyleData() const;

/*属性接口省略*/

protected:

    /// 获取默认头像路径

    /// \brief GetDefaultAvatar

    /// \param uSex

    /// \return

    ///

    QString GetDefaultAvatar(uint uSex) const;

    /// 获取元素矩形区域

    /// \brief GetElementRectan

    /// \param option

    /// \param index

    /// \param bGroup :是否为分组项

    /// \param nType,用户项索引“0:头像区域,1设备图标,2vip图标,3视频通话区域,4音频通话区域,5更多选项区域,6名称区域,7摘要区域”,分组项索引0节点图标,1名称,2统计数量

    /// \return

    ///

    virtual QRect GetElementRectan(const QStyleOptionViewItem &option,const QModelIndex &index,const bool bGroup,const int nType) const;

    /// 重写视图项尺寸定义

    virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const Q_DECL_OVERRIDE;

    /// 重写视图项编辑事件

    virtual bool editorEvent(QEvent *event,QAbstractItemModel *model,const QStyleOptionViewItem &option,const QModelIndex &index) override;

    /// 重写视图项辅助事件

    virtual bool helpEvent(QHelpEvent *event,QAbstractItemView *view,const QStyleOptionViewItem &option,const QModelIndex &index) override;

signals:

    /// 列表分组展开或收起

    /// \brief GroupItemsExpand

    /// \param bExpand 是否展开,true表示展开否则为收起

    /// \param uGroup :分组ID

    /// \param index  :模型索引ID

    ///

    void GroupItemsExpand(const bool &bExpand,const uint64_t uGroup, const QModelIndex &index);

    /// 列表视图元素单击事件信号

    /// 注意:调用SetHasMouseEvent(true)接口设置鼠标事件之后此信号将被发送

    /// \brief ItemsElementEvts

    /// \param nElement 元素索引定义[0:头像,1设备图标,2vip图标,3视频通话,4音频通话,5其它选项]

    /// \param index

    ///

    void ItemElementClick(const int &nElement,const QModelIndex &index);

    /// 列表视图元素双击事件信号

    /// 注意:调用SetHasMouseEvent(true)接口设置鼠标事件之后此信号将被发送

    /// \brief ItemElementDbClick

    /// \param nElement  0:头像,1设备图标,2vip图标,3视频通话,4音频通话,5其它选项

    /// \param index

    ///

    void ItemElementDbClick(const int &nElement,const QModelIndex &index);

    /// 分组右键单击事件

    /// \brief GroupsRightClicked

    /// \param tGroupInf

    /// \param point

    ///

    void GroupsRightClicked(const LNCFQFRIENDS_LISTGROUP &tGroupInf,const QPoint &point,const QModelIndex &index);

    /// 好友右键单击事件

    /// \brief UserRightClickEvts

    /// \param tUsersInf

    /// \param point

    ///

    void UserRightClickEvts(const LNCFQFRIENDS_LISTVIEWS &tUsersInf,const QPoint &point,const QModelIndex &index);

    /// 列表视图Ui元素鼠标悬停事件

    /// 注意:调用SetHasHoverEvent(true)接口设置悬停事件启用之后此信号将被发送

    /// \brief ItemsElementHovers

    /// \param nElement          元素索引定义[0:头像,1设备图标,2vip图标,3视频通话,4音频通话,5其它选项]

    /// \param index

    /// \param itemRect          当前项目矩形区域

    /// \param evtPos            鼠标悬停位置坐标[当前窗口]

    /// \param evtGlobalPos      鼠标悬停位置坐标[桌面窗口]

    ///

    void ItemsElementHovers(const int &nElement,const QModelIndex &index,const QRect &itemRect,const QPoint &evtPos,const QPoint &evtGlobalPos);

};

3、部分重要绘图部分代码

/// 绘制背景

/// \brief DrawBackgrounds

/// \param painter

/// \param option

/// \param bGroup

///

void Lncf_QFriendsItemd::DrawBackgrounds(QPainter *painter,const QStyleOptionViewItem &option,bool bGroup,bool bExpand) const

{

    painter->save();

    if(bGroup){

        QRect rcGroup;

        painter->setBrush(bExpand?this->tDelegateStyle.cGroupExpanClr:this->tDelegateStyle.cGroupBkgColor);

        if (option.state.testFlag(QStyle::State_MouseOver))

            painter->setBrush(!bExpand?this->tDelegateStyle.cGroupHoverClr:this->tDelegateStyle.cGroupExpHover);

        rcGroup = QRect(option.rect.left()+tDelegateStyle.uHorizeMarginG,option.rect.top()+tDelegateStyle.uVerticMarginG,option.rect.width()-tDelegateStyle.uHorizeMarginG*2,option.rect.height()-tDelegateStyle.uVerticMarginG*2);

        double dRadius = tDelegateStyle.dGroupRadiusId*rcGroup.height();

        painter->drawRoundedRect(rcGroup,dRadius,dRadius);

        if(tDelegateStyle.uGroupBorderId>0&&tDelegateStyle.uGroupBorderId<4)

        {

            painter->setBrush(Qt::NoBrush);

            QPen penBorder(tDelegateStyle.cGroupsBorders);

            penBorder.setWidthF(tDelegateStyle.fBordersWidths);

            painter->setPen(penBorder);

        }

        //分组边框风格,0不显示边框,1全部边框,2上,3下

        switch (tDelegateStyle.uGroupBorderId) {

        case 1:{

            painter->drawRoundedRect(rcGroup,dRadius,dRadius);

        }break;

        case 2:{

            painter->drawLine(rcGroup.left(),rcGroup.top()-tDelegateStyle.fBordersWidths,rcGroup.right(),rcGroup.top()-tDelegateStyle.fBordersWidths);

        }break;

        case 3:{

            painter->drawLine(rcGroup.left(),rcGroup.bottom()+1,rcGroup.right(),rcGroup.bottom()+1);

        }break;

        }

    }

    else{

        if(tDelegateStyle.bIconViewModel)

            painter->setBrush(Qt::transparent);

        else{

            painter->setBrush(this->tDelegateStyle.cItemsBkgColor);

            painter->drawRect(option.rect);

        }

        bool bDarw = true;

        painter->setPen(Qt::NoPen);

        if (option.state.testFlag(QStyle::State_MouseOver))

            painter->setBrush(!tDelegateStyle.bIconViewModel?tDelegateStyle.cItemsHoverClr:tDelegateStyle.cIconHoverClrs);

        if (option.state.testFlag(QStyle::State_Selected)){

            painter->setBrush(!tDelegateStyle.bIconViewModel?tDelegateStyle.cItemSelectClr:tDelegateStyle.cIconSelectClr);

            if(tDelegateStyle.bRoundAvtiveBg&&!tDelegateStyle.bIconViewModel){

                QRect rcBkg =option.rect;

                rcBkg.setLeft(rcBkg.left()+rcBkg.height()/2-1);

                QRect rcRnd =QRect(option.rect.left(),option.rect.top(),option.rect.height(),option.rect.height());

                painter->drawPie(rcRnd,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.cItemsHoverClr:tDelegateStyle.cIconHoverClrs);

        if(!tDelegateStyle.bIconViewModel){

            if(bDarw)

                painter->drawRect(option.rect);

        }

        else{

            painter->drawRoundedRect(option.rect, 5, 5);

        }

    }

    painter->restore();

}

/// 绘制分组项

/// \brief DrawItemsGroups

/// \param painter

/// \param option

/// \param itemData

///

void Lncf_QFriendsItemd::DrawItemsGroups(QPainter *painter,const QStyleOptionViewItem &option,bool bExpand,LNCFQFRIENDS_LISTGROUP itemData,const QModelIndex &index) const

{

    painter->save();

    (void)index;

    QRectF rcGroup,rcIcon,rcNode,rcText,rcCount;

    rcGroup = QRect(option.rect.left()+tDelegateStyle.uHorizeMarginG,option.rect.top()+tDelegateStyle.uVerticMarginG,option.rect.width()-tDelegateStyle.uHorizeMarginG*2,option.rect.height()-tDelegateStyle.uVerticMarginG*2);

    rcIcon = QRectF(rcGroup.left()+4,rcGroup.top()+rcGroup.height()/2-7,14,14);

    rcText = QRect(rcGroup.left()+25,rcGroup.top(),rcGroup.right()-50,rcGroup.height());

    rcNode = QRect(rcGroup.left()+7,rcGroup.top()+rcGroup.height()/2-4,8,8);

    QFont fontObj=painter->font();

    QFontMetrics fontMetrics(fontObj);

    fontObj.setPixelSize(7);

    QString sCount = QString("%1").arg(itemData.uGroupMemCount);

    int countWidth = fontMetrics.horizontalAdvance(sCount);

    if(this->bNavGroupStyle){

        rcCount = QRect(rcNode.left()+(this->tDelegateStyle.uGroupStyleIds==1?10:40),rcGroup.top()+rcGroup.height()/2-7,countWidth+7,14);

        painter->setPen(Qt::NoPen);

        painter->setBrush(bExpand?tDelegateStyle.cGroupNodesExp:tDelegateStyle.cGroupNodeBkgd);

        painter->drawEllipse(rcNode);

    }

    else{

        rcCount = QRect(rcGroup.right()-countWidth-11,rcGroup.top()+rcGroup.height()/2-8,countWidth+7,14);

        QImage icoNode = bExpand?pGroupExpanImg:pGroupCloseImg;

        if(icoNode.isNull())

            icoNode = bExpand?QImage(sGroupExpanImg):QImage(sGroupCloseImg);

        painter->drawImage(rcIcon, icoNode);

    }

    painter->setPen(tDelegateStyle.cGroupTxtColor);

    if (option.state.testFlag(QStyle::State_MouseOver))

        painter->setPen(tDelegateStyle.cGroupHoverTxt);

    if(bExpand)

        painter->setPen(tDelegateStyle.cGroupExpanTxt);

    if(this->tDelegateStyle.uGroupStyleIds==1)

        painter->drawText(rcText,Qt::AlignCenter,QString::fromStdU16String(itemData.sItemGroupName));

    else

        painter->drawText(rcText,Qt::AlignVCenter,QString::fromStdU16String(itemData.sItemGroupName));

    if(tDelegateStyle.bShowUserCount){

        painter->setPen(Qt::NoPen);

        painter->setBrush(tDelegateStyle.cGroupCountBkg);

        painter->drawRoundedRect(rcCount,rcCount.height()/2,rcCount.height()/2);

        painter->setPen(tDelegateStyle.cGroupCountTxt);

        painter->setFont(fontObj);

        painter->drawText(rcCount,Qt::AlignCenter,QString("%1").arg(itemData.uGroupMemCount));

    }

    painter->restore();

}

/// 绘制头部参考线

/// \brief DrawItemsHeader

/// \param painter

/// \param option

/// \param bGroup

///

void Lncf_QFriendsItemd::DrawItemsHeader(QPainter *painter,const QStyleOptionViewItem &option,bool bGroup,uint uStatus) const

{

    if(!this->tDelegateStyle.bIconViewModel){

        painter->save();

        //绘制辅助线

        QPen pen(tDelegateStyle.cItemHeadLines);

        pen.setWidthF(0.5F);

        switch (tDelegateStyle.nHeadeLineType) {

        case 0: pen.setStyle(Qt::SolidLine); break;

        case 1: pen.setStyle(Qt::DashLine); break;

        case 2: pen.setStyle(Qt::DotLine); break;

        case 3: pen.setStyle(Qt::DashDotLine); break;

        case 4: pen.setStyle(Qt::DashDotDotLine); break;

        }

        painter->setPen(pen);

        painter->setBrush(Qt::NoBrush);

        painter->drawLine(QPointF(option.rect.left()+11,option.rect.top()),QPointF(option.rect.left()+11,option.rect.bottom()));

        painter->drawLine(QPointF(option.rect.left(),option.rect.top()+option.rect.height()/2+pen.widthF()),QPointF(option.rect.left()+(bGroup?11:19),option.rect.top()+option.rect.height()/2+pen.widthF()));

        if(!bGroup)

        {

            painter->setPen(Qt::NoPen);

            painter->setBrush(tDelegateStyle.cUsersNodesClr);

            QRectF nodesRect = QRect(option.rect.left()+6, option.rect.top()+option.rect.height()/2-5, 10, 10);

            QRectF stateRect = QRect(option.rect.left()+6, option.rect.top()+option.rect.height()/2-5, 10, 10);

            if(uStatus>=0&&uStatus<8){

                painter->drawEllipse(nodesRect);

                ///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;

                }

            }

            else{

                painter->drawEllipse(stateRect);

            }

        }

        painter->restore();

    }

}

/// 绘制头像

/// \brief DrawItemsAavtar

/// \param painter

/// \param option

/// \param sImagePath

/// \param bHover

/// \param uSex

/// \param uStatus

/// \param uDevice

///

void Lncf_QFriendsItemd::DrawItemsAavtar(QPainter *painter,const QStyleOptionViewItem &option,std::u16string sImagePath,bool bHover,uint uSex,uint uStatus,std::u16string sName) 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()+20;

        if(option.rect.height()>41){

            avatarRect = QRect(leftMargin, option.rect.top()+5, option.rect.height()-10, option.rect.height()-10);

            borderRect = QRect(leftMargin-2, option.rect.top()+3, option.rect.height()-6, option.rect.height()-6);

            stateRect = QRect(leftMargin, option.rect.top()+5,12,12);

            stateFrm = QRect(leftMargin, option.rect.top()+5,12,12);

        }

        else{

            avatarRect = QRect(leftMargin, option.rect.top()+4, option.rect.height()-8, option.rect.height()-8);

            borderRect = QRect(leftMargin-2, option.rect.top()+2, option.rect.height()-4, option.rect.height()-4);

            stateRect = QRect(leftMargin, option.rect.top()+4,10,10);

            stateFrm = QRect(leftMargin, option.rect.top()+4,10,10);

        }

    }

    else{

        borderRect = QRect(option.rect.left()+8, option.rect.top()+8, this->tDelegateStyle.uIconGridWidth-16, this->tDelegateStyle.uIconGridWidth-16);

        avatarRect = QRect(option.rect.left()+12, option.rect.top()+12, this->tDelegateStyle.uIconGridWidth-24, this->tDelegateStyle.uIconGridWidth-24);

        stateRect = QRect(option.rect.left()+13, option.rect.top()+13,12,12);

        stateFrm = QRect(option.rect.left()+13, option.rect.top()+13,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.cItemsHoverClr);

            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);

    }

    //头像显示风格索引,0仅显示图像,无头像图像时显示默认头像,1无图像时显示名称第一字符,2仅显示名称第一字符

    switch (tDelegateStyle.bAvatarsStyles) {

    case 1:{

        painter->setBrush(tDelegateStyle.bRandomAvbgClr?QColor::fromHsl(rand()%360,rand()%256,rand()%200):tDelegateStyle.cAvatarBkgClrs);

        painter->drawRect(avatarRect);

        QImage imgAvatar = QImage(QString::fromStdU16String(sImagePath));

        if(imgAvatar.isNull()&&!sName.empty()){

            painter->setPen(this->tDelegateStyle.cItemsTxtColor);

            QFont fontObj=painter->font();

            fontObj.setPixelSize(avatarRect.height()/2.5);

            painter->setFont(fontObj);

            QString szName = QString::fromStdU16String(sName.substr(0,1));

            painter->drawText(avatarRect,Qt::AlignCenter,szName);

        }

        else{

            if(imgAvatar.isNull())

                imgAvatar = QImage(GetDefaultAvatar(uSex));

            if((uStatus==0||uStatus==5)&&tDelegateStyle.bGrayAvatarImg)

                imgAvatar = imgAvatar.convertToFormat(QImage::Format_Grayscale8,Qt::AutoColor);

            painter->drawImage(avatarRect, imgAvatar);

        }

    }break;

    case 2:{

        painter->setBrush(tDelegateStyle.bRandomAvbgClr?QColor::fromHsl(rand()%360,rand()%256,rand()%200):tDelegateStyle.cAvatarBkgClrs);

        painter->drawRect(avatarRect);

        QString szName = QString::fromStdU16String(sName.substr(0,1));

        painter->setPen(this->tDelegateStyle.cItemsTxtColor);

        QFont fontObj=painter->font();

        fontObj.setPixelSize(avatarRect.height()/2.5);

        painter->setFont(fontObj);

        painter->drawText(avatarRect,Qt::AlignCenter,szName.isEmpty()?"#":szName);

    }break;

    default:{

        painter->setBrush(tDelegateStyle.cAvatarBkgClrs);

        painter->drawRect(avatarRect);

        QImage imgAvatar = QImage(QString::fromStdU16String(sImagePath));

        if(imgAvatar.isNull())

            imgAvatar = QImage(GetDefaultAvatar(uSex));

        if((uStatus==0||uStatus==5)&&tDelegateStyle.bGrayAvatarImg)

            imgAvatar = imgAvatar.convertToFormat(QImage::Format_Grayscale8,Qt::AutoColor);

        painter->drawImage(avatarRect, imgAvatar);

    };break;

    }

    painter->restore();

    if((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();

    }

}

4、事件和其他代码示例

/// 重写视图项尺寸定义

QSize Lncf_QFriendsItemd::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const

{

    //如果是分组

    Q_UNUSED(index)

    auto size =  QStyledItemDelegate::sizeHint(option, index);

    if(index.data(LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE).toBool()){

        Lncf_QFriendsListv *pListView = static_cast<Lncf_QFriendsListv *>(index.model()->parent());

        if(pListView) {

            return QSize(pListView->viewport()->width(), tDelegateStyle.bIconViewModel?this->tDelegateStyle.uGroupsHeights*1.5:this->tDelegateStyle.uGroupsHeights);

        }

    }

    else{ //如果是用户

        if(!tDelegateStyle.bIconViewModel){

            uint uRowHeight = this->tDelegateStyle.uItemHeightVal;

            if(this->tDelegateStyle.uItemsStyleIds==1)

                uRowHeight = index.data(LQFRIENDSLIST_ROLES::FRIENDSLIST_ACTIV).toBool()?this->tDelegateStyle.uItemHeightVal:this->tDelegateStyle.uItemMinHeight;

            return QSize(option.rect.width(), uRowHeight);

        }

        else

        {

            //size.rheight() = uIconGridHeigh;

            return QSize(this->tDelegateStyle.uIconGridWidth, this->tDelegateStyle.uIconGridHeigh);

        }

    }

    return  size;

}

/// 重写视图项编辑事件

bool Lncf_QFriendsItemd::editorEvent(QEvent *event,QAbstractItemModel *model,const QStyleOptionViewItem &option,const QModelIndex &index)

{

    if(index.isValid())

    {

        auto mouseEvent = static_cast<QMouseEvent *>(event);

        if(!mouseEvent) {

            return QStyledItemDelegate::editorEvent(event, model, option, index);

        }

        //判断是分组还是用户

        if(index.data(LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE).toBool())

        {

            QVariant  varGroup = index.data(LQFRIENDSLIST_ROLES::FRIENDSLIST_GROUP);

            LNCFQFRIENDS_LISTGROUP ItemGroupData = varGroup.value<LNCFQFRIENDS_LISTGROUP>();

            //printf("group id:%zd,expand:%d\n",ItemGroupData.uItemsGroupIds,bExpand);

            switch (mouseEvent->type()) {

            case QEvent::MouseMove:

            {

            }break;

            case QEvent::MouseButtonRelease:

            {

                if(mouseEvent->button() != Qt::LeftButton){

                    //分组右键单击事件

                    emit GroupsRightClicked(ItemGroupData,mouseEvent->globalPos(),index);

                    return QStyledItemDelegate::editorEvent(event, model, option, index);

                }


            }break;

            case QEvent::MouseButtonDblClick:

            {

                if(mouseEvent->button() != Qt::LeftButton){

                    return QStyledItemDelegate::editorEvent(event, model, option, index);

                }

                if(this->tDelegateStyle.uExpandGroupId>1&&this->tDelegateStyle.uExpandGroupId<4){

                    bool bExpand = index.data(LQFRIENDSLIST_ROLES::FRIENDSLIST_EXPAN).toBool();

                    if(this->tDelegateStyle.uExpandGroupId==2){

                        if(GetElementRectan(option, index,true, 0).contains(mouseEvent->pos()))

                        {

                            model->setData(index, bExpand?false:true, LQFRIENDSLIST_ROLES::FRIENDSLIST_EXPAN);

                            emit GroupItemsExpand(bExpand?false:true,!bNavGroupStyle?ItemGroupData.uItemsGroupIds:index.data(LQFRIENDSLIST_ROLES::FRIENDSLIST_INDEX).toULongLong(),index);

                            break;

                        }

                    }

                    if(this->tDelegateStyle.uExpandGroupId==3)

                    {

                        model->setData(index, bExpand?false:true, LQFRIENDSLIST_ROLES::FRIENDSLIST_EXPAN);

                        emit GroupItemsExpand(bExpand?false:true,!bNavGroupStyle?ItemGroupData.uItemsGroupIds:index.data(LQFRIENDSLIST_ROLES::FRIENDSLIST_INDEX).toULongLong(),index);

                        break;

                    }

                }

            }break;

            }

        }

        else{

            if(this->bHasMouseEvent){

                {

                    model->setData(index, false, LQFRIENDSLIST_ROLES::FRIENDAVATAR_HOVER);                    // 鼠标移入头像

                    model->setData(index, false, LQFRIENDSLIST_ROLES::FRIENDVIPICO_HOVER);                    // 鼠标移入VIP按钮

                    model->setData(index, false, LQFRIENDSLIST_ROLES::FRIENDDEVICE_HOVER);                    // 鼠标移入设备按钮

                    model->setData(index, false, LQFRIENDSLIST_ROLES::FRIENDRSUMARY_HOVER);                    // 鼠标移入摘要数据区域

                    model->setData(index, false, LQFRIENDSLIST_ROLES::FRIENDVIDEOS_HOVER);                    // 鼠标移入视频通话按钮区域

                    model->setData(index, false, LQFRIENDSLIST_ROLES::FRIENDAUDIOS_HOVER);                    // 鼠标移入音频通话按钮区域

                    model->setData(index, false, LQFRIENDSLIST_ROLES::FRIENDSMORES_HOVER);                    // 鼠标移入更多选项按钮区域

                }

                QVariant  varUsers = index.data(LQFRIENDSLIST_ROLES::FRIENDSLIST_ITEMS);

                LNCFQFRIENDS_LISTVIEWS ItemUsersData = varUsers.value<LNCFQFRIENDS_LISTVIEWS>();

                //0:头像区域,1设备图标,2vip图标,3视频通话区域,4音频通话区域,5更多选项区域,6名称区域,7摘要区域”,分组项索引0节点图标,1名称,2统计数量

                switch (mouseEvent->type()) {

                case QEvent::MouseMove:

                {

                    if(bShowItemsTips)QToolTip::hideText();

                    //鼠标移入设备图标区域

                    auto device_hover = GetElementRectan(option, index,false, 1).contains(mouseEvent->pos());

                    model->setData(index, (ItemUsersData.uDeviceTypeIds>=0&&ItemUsersData.uDeviceTypeIds<4)?device_hover:false, LQFRIENDSLIST_ROLES::FRIENDDEVICE_HOVER);


                }break;

                case QEvent::MouseButtonRelease:

                {

                    //发送头像区域单击信号

                    if(GetElementRectan(option, index,false, 0).contains(mouseEvent->pos()))

                    {

                        emit ItemElementClick(0,index);

                        return QStyledItemDelegate::editorEvent(event, model, option, index);

                    }

                    model->setData(index,true,LQFRIENDSLIST_ROLES::FRIENDSLIST_CLICK);

                }break;


                }

            }

        }

    }

    return QStyledItemDelegate::editorEvent(event, model, option, index);

}

5、受限于篇幅限制,无法提供所有代码。上面只是委托绘制代码,下面为列表部分头文件代码

class LNCF_QTSOCIALLIBS_API Lncf_QFriendsListv : public Lncf_IndexNavListv

{

    Q_OBJECT

    Q_PROPERTY(QString sDevicePcIcons READ GetDevicePcIcons WRITE SetDevicePcIcons)  //PC客户端图标

    Q_PROPERTY(QString sDeviceMbIcons READ GetDeviceMbIcons WRITE SetDeviceMbIcons)  //手机客户端图标

    Q_PROPERTY(QString sDeviceWbIcons READ GetDeviceWbIcons WRITE SetDeviceWbIcons)  //web客户端图标

    Q_PROPERTY(QString sOtherAppIcons READ GetOtherAppIcons WRITE SetOtherAppIcons)  //其它应用图标

    Q_PROPERTY(QString sVipLogoImages READ GetVipLogoImages WRITE SetVipLogoImages)  //会员图标

    Q_PROPERTY(QString sSvipLogoImage READ GetSvipLogoImage WRITE SetSvipLogoImage)  //超级会员图标

    Q_PROPERTY(QString sOnlineImgLogo READ GetOnlineImgLogo WRITE SetOnlineImgLogo)  //在线状态图标

    Q_PROPERTY(QString sOffLineImages READ GetOffLineImages WRITE SetOffLineImages)  //离线状态图标

    Q_PROPERTY(QString sLeaveLogosImg READ GetLeaveLogosImg WRITE SetLeaveLogosImg)  //离开状态图标

    Q_PROPERTY(QString sBusyStatusImg READ GetBusyStatusImg WRITE SetBusyStatusImg)  //忙碌状态图标

    Q_PROPERTY(QString sStealthImages READ GetStealthImages WRITE SetStealthImages)  //隐身状态图标

    Q_PROPERTY(QString sNotDisturbImg READ GetNotDisturbImg WRITE SetNotDisturbImg)  //勿扰状态图标

    Q_PROPERTY(QString sCustomizeImgs READ GetCustomizeImgs WRITE SetCustomizeImgs)  //自定义状态图标

    Q_PROPERTY(QString sCallMeStatImg READ GetCallMeStatImg WRITE SetCallMeStatImg)  //与我联系状态图标

    Q_PROPERTY(QString sSourceAppsImg READ GetSourceAppsImg WRITE SetSourceAppsImg)  //默认来源应用图标

    Q_PROPERTY(QString sGroupExpanImg READ GetGroupExpanImg WRITE SetGroupExpanImg)  //分组展开图标

    Q_PROPERTY(QString sGroupCloseImg READ GetGroupCloseImg WRITE SetGroupCloseImg)  //分组关闭图标

    Q_PROPERTY(QString sVideoChatImgs READ GetVideoChatImgs WRITE SetVideoChatImgs)  //视频会话图标

    Q_PROPERTY(QString sAudioChatImgs READ GetAudioChatImgs WRITE SetAudioChatImgs)  //音频通话图标

    Q_PROPERTY(QString sMoreOptionImg READ GetMoreOptionImg WRITE SetMoreOptionImg)  //更多选项图标

    Q_PROPERTY(bool bHasMouseEvent READ GetItemsMouseEvt WRITE SetItemsMouseEvt)    //是否启用鼠标事件

    Q_PROPERTY(bool bHasHoverEvent READ GetHasHoverEvent WRITE SetHasHoverEvent)    //是否处理鼠标悬停事件

    Q_PROPERTY(bool bShowItemsTips READ GetShowItemsTips WRITE SetShowItemsTips)      //是否显示鼠标悬停时提示信息

    Q_PROPERTY(uint uGroupStyleIds READ GetGroupStyleIds WRITE SetGroupStyleIds)      //分组风格

    Q_PROPERTY(uint uItemsStyleIds READ GetItemsStyleIds WRITE SetItemsStyleIds)      //列表项风格

    Q_PROPERTY(uint uExpandGroupId READ GetExpandGroupId WRITE SetExpandGroupId)      //展开和闭合分组操作方式

    Q_PROPERTY(uint uUserRowHeight READ GetUserRowHeight WRITE SetUserRowHeight);    //好友行高

    Q_PROPERTY(uint uGroupsHeights READ GetGroupsHeights WRITE SetGroupsHeights);    //分组项行高

    Q_PROPERTY(bool bNavGroupStyle READ GetNavGroupStyle WRITE SetNavGroupStyle);    //分组类别

    Q_PROPERTY(bool bHasOnlyOnline READ GetHasOnlyOnline WRITE SetHasOnlyOnline);    //显示联机用户或全部

    Q_PROPERTY(bool bShowGroupItem READ GetShowGroupItem WRITE SetShowGroupItem);    //是否显示好友分组

public:

    explicit Lncf_QFriendsListv(QWidget *parent = nullptr);

    ~ Lncf_QFriendsListv();

protected:

    /// 初始化列表虚函数

    /// \brief InitFriendsList

    ///

    virtual void InitFriendsList();

private:

    /// 初始导航组

    /// \brief InitNavigatGroup

    ///

    void InitNavigatGroup();

private:

    QStandardItemModel *pListItemModel = nullptr;    //列表模型对象指针

    Lncf_QFriendsItemd *pItemsDelegate = nullptr;    //列表项委托对象指针

    Lncf_QFriendSortlm *pSortFilteMode = nullptr;    //列表筛选器模型对象指针

    /// 是否启用鼠标跟踪

    /// \brief bMouseTracking

    ///

    bool                bMouseTracking = false;

    /// 是否为索引分组类别,如果为索引分组则不显示用户分组,而是以A-Z的字母顺序分组

    /// \brief bNavGroupStyle

    ///

    bool                bNavGroupStyle = false;

    /// 仅显示在线用户

    /// \brief bHasOnlyOnline

    ///

    bool                bHasOnlyOnline = false;

    /// 是否显示分组

    /// \brief bShowGroupItem

    ///

    bool                bShowGroupItem = true;

    /// 导航分组是否初始化

    /// \brief bInitNaviGroup

    ///

    bool                bInitNaviGroup = false;

    /// 索引分组文本

    /// \brief sNaviTextsList

    ///

    QList<std::u16string>  sNaviTextsList;

public:

    /// 获取指定索引模型分组数据

    /// \brief GetItemsViewData

    /// \param index

    /// \return

    ///

    LNCFQFRIENDS_LISTGROUP GetItemGroupData(const QModelIndex &index) const;

    /// 获取指定索引模型视图数据

    /// \brief GetItemsViewData

    /// \param index

    /// \return

    ///

    LNCFQFRIENDS_LISTVIEWS GetItemsUserData(const QModelIndex &index) const;

    /// 获取指定索引模型自定义应用数据

    /// \brief GetItemsAppsData

    /// \param index

    /// \param bGroup :是否为分组项

    /// \return

    ///

    QVariant GetItemsAppsData(const QModelIndex &index,bool &bGroup) const;

    /// 获取会话列表所有数据链表

    /// \brief GetItemsDataList

    /// \param vList

    /// \return

    ///

    bool GetItemsDataList(std::vector<LNCFQFRIENDS_LISTDATAS> &vList);

public:

    实现QListView函数//

    void setViewMode(ViewMode mode);

    void setSpacing(int space);

    void setGridSize(const QSize &size);

public:

    /// 添加好友列表分组

    /// \brief AddFriendsGroup

    /// \param data

    /// \param appData

    ///

    void AddFriendsGroup(LNCFQFRIENDS_LISTGROUP data);

    /// 添加会话项目

    /// \brief AddSessionItems

    /// \param data    :默认视图数据

    /// \param appData  :自定义app数据,此数据由app自行维护,默认情况下此数据不赋值

    ///

    void AddFriendsUsers(LNCFQFRIENDS_LISTVIEWS data);

    /// 添加一个好友分组列表项

    /// \brief AddFriendsLists

    /// \param data

    ///

    void AddFriendsLists(LNCFQFRIENDS_LISTDATAS data);

    /// 设置会话列表数据集合

    /// \brief SetSessionDatas

    /// \param vList  : 包含两条数据属性,1视图数据(LNCFQSESSION_VIEWDATAS),2应用自定义数据(QVariant)

    ///

    void SetFriendsDatas(std::vector<LNCFQFRIENDS_LISTDATAS> &vList);

    /// 删除分组,如果该分组有成员则不会被删除

    /// \brief RemoveGroupData

    /// \param uGroupID :分组ID

    /// \param uErrMsg  :返回错误引用参数

    /// \return

    ///

    bool RemoveGroupData(uint64_t uGroupID,std::u16string &uErrMsg);

    /// 删除好友成员

    /// \brief RemoveUsersData

    /// \param tUserInf:为指定的好友数据结构,只用到了此结构体的三个变量,gViewsItemsIds;uViewsItemsIds;sViewsItemsIds;

    /// \param uErrMsg :返回错误引用参数

    /// \return

    ///

    bool RemoveUsersData(LNCFQFRIENDS_LISTVIEWS tUserInf,std::u16string &uErrMsg);

    /// 移动用户分组

    /// \brief MoveUsersGroups

    /// \param tUserInf

    /// \param uOldGroupId

    /// \param uNewGroupId

    /// \return

    ///

    bool MoveUsersGroups(LNCFQFRIENDS_LISTVIEWS tUserInf,uint64_t uOldGroupId,uint64_t uNewGroupId,std::u16string &uErrMsg);

    /// 好友数据是否存在

    /// \brief HasFriendsExist

    /// \param data

    /// \return

    ///

    bool HasFriendsExist(LNCFQFRIENDS_LISTDATAS data);

    /// 检查目标属性分组是否存在。主要检查分组ID

    /// \brief HasGroupsExists

    /// \param data

    /// \return

    ///

    bool HasGroupsExists(LNCFQFRIENDS_LISTGROUP data);

    /// 检查目标联系人属性是否存在,检查三个itemid属性

    /// \brief HasContactExist

    /// \param data,主要用结构体三个参数:gViewsItemsIds,uViewsItemsIds,sViewsItemsIds

    /// \return

    ///

    bool HasContactExist(LNCFQFRIENDS_LISTVIEWS data);

    /// 更新用户数据

    /// \brief UpdateUserDatas

    /// \param data    :默认视图数据

    ///

    bool UpdateUsersData(LNCFQFRIENDS_LISTVIEWS data,std::u16string &uErrMsg);

    /// 更新分组数据

    /// \brief UpdateGroupData

    /// \param data    :默认视图数据

    ///

    bool UpdateGroupData(LNCFQFRIENDS_LISTGROUP data,std::u16string &uErrMsg);

    /// 根据模型索引更新模型用户数据

    /// \brief UpdateUsersData

    /// \param index    :索引ID

    /// \param data    :视图数据

    ///

    bool UpdateUsersData(const QModelIndex &index,LNCFQFRIENDS_LISTVIEWS data,std::u16string &uErrMsg);

    /// 根据模型索引更新模型分组数据

    /// \brief UpdateUsersData

    /// \param index    :索引ID

    /// \param data    :视图数据

    ///

    bool UpdateGroupData(const QModelIndex &index,LNCFQFRIENDS_LISTGROUP data,std::u16string &uErrMsg);

    /// 设置目标索引的自定义app数据

    /// \brief SetItemAppsData

    /// \param index    :模型索引ID

    /// \param appData  :应用数据,数据设置不会查重,而是直接替换原有数据[如果存在]。因此如果有必要请先获取然后在写入

    ///

    bool SetItemAppsData(const QModelIndex &index,QVariant appData,std::u16string &uErrMsg);

    /// 激活指定的用户项

    /// \brief ActiveUsersItem

    /// \param tagUser

    ///

    bool ActiveUsersItem(const LNCFQFRIENDS_LISTVIEWS tagUser,std::u16string &uErrMsg);

    /// 更新列表风格

    /// \brief UpdateListDatas

    ///

    void UpdateListDatas();

    /// 展开所有节点

    /// \brief ExpandAllsNodes

    ///

    void ExpandAllsNodes();

    /// 闭合所有节点

    /// \brief ClosureAllNodes

    ///

    void ClosureAllNodes();

    /// 获取联系人总数

    /// \brief GetFriendsCount

    /// \return

    ///

    uint64_t GetFriendsCount();

public:

/*属性代码段省略*/

private slots:

    /// 处理分组展开或收起

    /// \brief HandGroupsExpand

    /// \param bExpand 是否展开,true表示展开否则为收起

    /// \param uGroup :分组ID

    /// \param index  :模型索引ID

    ///

    void HandGroupsExpand(const bool &bExpand,const uint64_t uGroup, const QModelIndex &index);

    /// 处理列表项单击

    /// \brief HandItemsClicked

    /// \param index

    ///

    void HandItemsClicked(const QModelIndex &index);

protected:

    void resizeEvent(QResizeEvent *event) override;

private slots:

    /// 列表视图元素单击事件槽

    /// \brief ItemsElementEvts

    /// \param nElement 元素索引定义[0:头像,1设备图标,2vip图标,3未读消息,4屏蔽按钮]

    /// \param index

    ///

    void OnUserElementClick(const int &nElement,const QModelIndex &index);

    /// 列表视图元素双击事件槽

    /// \brief ItemElementDbClick

    /// \param nElement

    /// \param index

    ///

    void OnUserElementDbClick(const int &nElement,const QModelIndex &index);

    /// 列表视图Ui元素鼠标悬停事件

    /// \brief OnElementsHovers

    /// \param nElement          元素索引定义 0:头像,1设备图标,2vip图标,3视频通话,4音频通话,5其它选项

    /// \param index

    /// \param itemRect          当前项目矩形区域

    /// \param evtPos            鼠标悬停位置坐标[当前窗口]

    /// \param evtGlobalPos      鼠标悬停位置坐标[桌面窗口]

    ///

    void OnUserElementsHovers(const int &nElement,const QModelIndex &index,const QRect &itemRect,const QPoint &evtPos,const QPoint &evtGlobalPos);

    /// 分组右键单击事件

    /// \brief OnGroupRightClick

    /// \param tGroupInf

    /// \param point

    ///

    void OnGroupRightClick(const LNCFQFRIENDS_LISTGROUP &tGroupInf,const QPoint &point,const QModelIndex &index);

    /// 好友右键单击事件

    /// \brief OnUsersRightClick

    /// \param tUsersInf

    /// \param point

    ///

    void OnUsersRightClick(const LNCFQFRIENDS_LISTVIEWS &tUsersInf,const QPoint &point,const QModelIndex &index);

    /// 处理导航按钮选中事件

    /// \brief NaviBtnCheckEvts

    /// \param uIndex :选中的按钮索引0表示所有#按钮,1-26表示字母A到Z,27=数字按钮,28=其它按钮

    ///

    void OnNaviBtnCheckEvt(const uint uIndex);

};

6、列表部分实现代码

Lncf_QFriendsListv::Lncf_QFriendsListv(QWidget *parent)

    :Lncf_IndexNavListv(parent)

{

    this->InitNavBaseList(false,false);

    this->InitFriendsList();

}

Lncf_QFriendsListv::~Lncf_QFriendsListv()

{

}

/// 初始化列表虚函数

/// \brief InitFriendsList

///

void Lncf_QFriendsListv::InitFriendsList()

{

    sNaviTextsList = {u"A",u"B",u"C",u"D",u"E",u"F",u"G",u"H",u"I",u"J",u"K",u"L",u"M",u"N",u"O",u"P",u"Q",u"R",u"S",u"T",u"U",u"V",u"W",u"X",u"Y",u"Z",u"❉",u"☼"};

    SetNavPaddingVal(9);

    pItemsDelegate = new Lncf_QFriendsItemd(this);

    this->setItemDelegate(pItemsDelegate);

    pListItemModel = new QStandardItemModel(this);

    pSortFilteMode = new Lncf_QFriendSortlm(this);

    pSortFilteMode->setSourceModel(pListItemModel);            //将model放入代理中

    this->setModel(pSortFilteMode);                            //在视图中安装代理

    connect(pItemsDelegate, &Lncf_QFriendsItemd::GroupItemsExpand, this, &Lncf_QFriendsListv::HandGroupsExpand);

    connect(pItemsDelegate, &Lncf_QFriendsItemd::ItemElementClick, this, &Lncf_QFriendsListv::OnUserElementClick);

    connect(pItemsDelegate, &Lncf_QFriendsItemd::ItemElementDbClick, this, &Lncf_QFriendsListv::OnUserElementDbClick);

    connect(pItemsDelegate, &Lncf_QFriendsItemd::ItemsElementHovers, this, &Lncf_QFriendsListv::OnUserElementsHovers);

    connect(pItemsDelegate, &Lncf_QFriendsItemd::GroupsRightClicked, this, &Lncf_QFriendsListv::OnGroupRightClick);

    connect(pItemsDelegate, &Lncf_QFriendsItemd::UserRightClickEvts,this, &Lncf_QFriendsListv::OnUsersRightClick);

    connect(this, &Lncf_IndexNavListv::clicked, this, &Lncf_QFriendsListv::HandItemsClicked);

    connect(this, &Lncf_IndexNavListv::NavBtnCheckEvts, this, &Lncf_QFriendsListv::OnNaviBtnCheckEvt);

    this->setEditTriggers(QAbstractItemView::NoEditTriggers);

    this->setResizeMode(Lncf_IndexNavListv::Adjust );

    this->SetItemsMouseEvt(bMouseTracking);

    this->setVerticalScrollMode(ScrollPerPixel);

}

/// 初始导航组

/// \brief InitNavigatGroup

///

void Lncf_QFriendsListv::InitNavigatGroup()

{

    // A~Z

    for(int i = 0; i < 26; i++)

    {

        QLatin1Char ch(i + 65);

        auto itemGroup = new QStandardItem(QString(ch));

        itemGroup->setData(true, LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE);

        LNCFQFRIENDS_LISTGROUP groupData;

        groupData.uItemsNavIndex = i+1;

        groupData.uItemsGroupIds = i+65;

        groupData.sItemGroupName = sNaviTextsList[i];

        itemGroup->setData(i+1,LQFRIENDSLIST_ROLES::FRIENDSLIST_INDEX);

        itemGroup->setData(QVariant::fromValue(groupData), LQFRIENDSLIST_ROLES::FRIENDSLIST_GROUP);

        itemGroup->setData(true, LQFRIENDSLIST_ROLES::FRIENDSLIST_EXPAN);

        itemGroup->setData(1, LQFRIENDSLIST_ROLES::FRIENDGROUP_TYPES);

        itemGroup->setData(0, LQFRIENDSLIST_ROLES::FRIENDGROUP_DATAS);

        itemGroup->setData((i+1)*100, LQFRIENDSLIST_ROLES::FRIENDINDEX_DATAS);

        pListItemModel->appendRow(itemGroup);

    }

    //数字开头,标识为❉, 索引未26

    auto itemNumber = new QStandardItem(QString::fromStdU16String(sNaviTextsList[26]));

    itemNumber->setData(true, LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE);

    LNCFQFRIENDS_LISTGROUP numberData;

    numberData.uItemsNavIndex = 27;

    numberData.uItemsGroupIds = 26+65;

    numberData.sItemGroupName = sNaviTextsList[26];

    itemNumber->setData(QVariant::fromValue(numberData), LQFRIENDSLIST_ROLES::FRIENDSLIST_GROUP);

    itemNumber->setData(true, LQFRIENDSLIST_ROLES::FRIENDSLIST_EXPAN);

    itemNumber->setData(1, LQFRIENDSLIST_ROLES::FRIENDGROUP_TYPES);

    itemNumber->setData(27,LQFRIENDSLIST_ROLES::FRIENDSLIST_INDEX);

    itemNumber->setData(0, LQFRIENDSLIST_ROLES::FRIENDGROUP_DATAS);

    itemNumber->setData(27*100, LQFRIENDSLIST_ROLES::FRIENDINDEX_DATAS);

    pListItemModel->appendRow(itemNumber);

    //其它字符以☼表示,索引为27

    auto itemOther = new QStandardItem(QString::fromStdU16String(sNaviTextsList[27]));

    itemOther->setData(true, LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE);

    LNCFQFRIENDS_LISTGROUP otherData;

    otherData.uItemsNavIndex = 28;

    otherData.uItemsGroupIds = 27+65;

    otherData.sItemGroupName = sNaviTextsList[27];

    itemOther->setData(QVariant::fromValue(otherData), LQFRIENDSLIST_ROLES::FRIENDSLIST_GROUP);

    itemOther->setData(true, LQFRIENDSLIST_ROLES::FRIENDSLIST_EXPAN);

    itemOther->setData(1, LQFRIENDSLIST_ROLES::FRIENDGROUP_TYPES);

    itemOther->setData(28,LQFRIENDSLIST_ROLES::FRIENDSLIST_INDEX);

    itemOther->setData(0, LQFRIENDSLIST_ROLES::FRIENDGROUP_DATAS);

    itemOther->setData(28*100, LQFRIENDSLIST_ROLES::FRIENDINDEX_DATAS);

    pListItemModel->appendRow(itemOther);

    bInitNaviGroup = true;

}

/// 获取指定索引模型分组数据

/// \brief GetItemsViewData

/// \param index

/// \return

///

LNCFQFRIENDS_LISTGROUP Lncf_QFriendsListv::GetItemGroupData(const QModelIndex &index) const

{

    if(index.isValid()&&pSortFilteMode->data(index,LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE).toBool())

    {

        return  pSortFilteMode->data(index,LQFRIENDSLIST_ROLES::FRIENDSLIST_GROUP).value<LNCFQFRIENDS_LISTGROUP>();

    }

    return LNCFQFRIENDS_LISTGROUP();

}

/// 获取指定索引模型视图数据

/// \brief GetItemsViewData

/// \param index

/// \return

///

LNCFQFRIENDS_LISTVIEWS Lncf_QFriendsListv::GetItemsUserData(const QModelIndex &index) const

{

    if(index.isValid()&&!pSortFilteMode->data(index,LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE).toBool())

    {

        return  pSortFilteMode->data(index,LQFRIENDSLIST_ROLES::FRIENDSLIST_ITEMS).value<LNCFQFRIENDS_LISTVIEWS>();

    }

    return LNCFQFRIENDS_LISTVIEWS();

}

/// 获取指定索引模型自定义应用数据

/// \brief GetItemsAppsData

/// \param index

/// \return

///

QVariant Lncf_QFriendsListv::GetItemsAppsData(const QModelIndex &index,bool &bGroup) const

{

    if(index.isValid())

    {

        bGroup = pSortFilteMode->data(index,LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE).toBool();

        if(bGroup)

            return  pSortFilteMode->data(index,LQFRIENDSLIST_ROLES::FRIENDSLIST_GROUP).value<LNCFQFRIENDS_LISTGROUP>().tGroupAppsData;

        else

            return  pSortFilteMode->data(index,LQFRIENDSLIST_ROLES::FRIENDSLIST_ITEMS).value<LNCFQFRIENDS_LISTVIEWS>().tItemsAppsData;

    }

    return QVariant();

}

/// 获取会话列表所有数据链表

/// \brief GetItemsDataList

/// \param vList

/// \return

///

bool Lncf_QFriendsListv::GetItemsDataList(std::vector<LNCFQFRIENDS_LISTDATAS> &vList)

{

    int rowCount = pSortFilteMode->rowCount();

    for(int i=0;i<rowCount;i++)  //mIndex 是用来保存我加入项目的个数。。

    {

        QModelIndex Index = pSortFilteMode->index(i, 0);

        if(Index.isValid()){

            LNCFQFRIENDS_LISTDATAS tagItemData;

            if(pSortFilteMode->data(Index,LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE).toBool()&&pSortFilteMode->data(Index,LQFRIENDSLIST_ROLES::FRIENDGROUP_TYPES).toUInt()==0){

                tagItemData.tFriendsGroups = pSortFilteMode->data(Index,LQFRIENDSLIST_ROLES::FRIENDSLIST_GROUP).value<LNCFQFRIENDS_LISTGROUP>();

                LNCFQFRIENDS_LISTVIEWS itemView;

                for(int x=0;x<rowCount;x++)  //mIndex 是用来保存我加入项目的个数。。

                {

                    QModelIndex sIndex = pSortFilteMode->index(x, 0);

                    if(!pSortFilteMode->data(sIndex,LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE).toBool()){

                        itemView = pSortFilteMode->data(sIndex,LQFRIENDSLIST_ROLES::FRIENDSLIST_ITEMS).value<LNCFQFRIENDS_LISTVIEWS>();

                        tagItemData.vSubsListItems.push_back(itemView);

                    }

                }

            }

            vList.push_back(tagItemData);

        }

    }

    return vList.size()>0;

}

实现QListView函数//

void Lncf_QFriendsListv::setViewMode(ViewMode mode)

{

    if(mode==Lncf_IndexNavListv::IconMode){

        pItemsDelegate->SetHasIconsModel(true);

        this->setContentsMargins(3,3,3,3);

        this->update();

    }

    else{

        pItemsDelegate->SetHasIconsModel(false);

        this->setContentsMargins(1,1,1,1);

    }

    Lncf_IndexNavListv::setViewMode(mode);

}

void Lncf_QFriendsListv::setSpacing(int space)

{

    Lncf_IndexNavListv::setSpacing(space);

}

void Lncf_QFriendsListv::setGridSize(const QSize &size)

{

    pItemsDelegate->SetIconsGridSize(size.width(),size.height());

    //QListView::setGridSize(size);

}

/// 添加好友列表分组

/// \brief AddFriendsGroup

/// \param data

/// \param appData

///

void Lncf_QFriendsListv::AddFriendsGroup(LNCFQFRIENDS_LISTGROUP data)

{

    if(HasGroupsExists(data))

        return;

    QStandardItem *pItem = new QStandardItem;

    pItem->setData(true, LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE);

    pItem->setData(true, LQFRIENDSLIST_ROLES::FRIENDSLIST_EXPAN);

    pItem->setData(0, LQFRIENDSLIST_ROLES::FRIENDGROUP_TYPES);

    pItem->setData(data.uItemsGroupIds+1*10, LQFRIENDSLIST_ROLES::FRIENDGROUP_DATAS);

    pItem->setData(0, LQFRIENDSLIST_ROLES::FRIENDINDEX_DATAS);

    pItem->setData(QVariant::fromValue(data), LQFRIENDSLIST_ROLES::FRIENDSLIST_GROUP);

    pListItemModel->appendRow(pItem);

    UpdateListDatas();

}

/// 添加会话项目

/// \brief AddSessionItems

/// \param data    :默认视图数据

/// \param appData  :自定义app数据,此数据由app自行维护,默认情况下此数据不赋值

///

void Lncf_QFriendsListv::AddFriendsUsers(LNCFQFRIENDS_LISTVIEWS data)

{

    if(HasContactExist(data))

        return;

    QString sName = QString::fromStdU16String(data.uItemsShowName);

    QStandardItem *pUserItem = new QStandardItem(sName);

    pUserItem->setData(false, LQFRIENDSLIST_ROLES::FRIENDSLIST_HEADE);

    pUserItem->setData(false, LQFRIENDSLIST_ROLES::FRIENDSLIST_ACTIV);

    pUserItem->setData(false, LQFRIENDSLIST_ROLES::FRIENDSLIST_CLICK);

    pUserItem->setData(data.uItemsGroupIds+1*10+1, LQFRIENDSLIST_ROLES::FRIENDGROUP_DATAS);

    pUserItem->setData(Lncf_NavCharHelper::GetNavigateIndexVal(sName.at(0)),LQFRIENDSLIST_ROLES::FRIENDSLIST_INDEX);

    pUserItem->setData(Lncf_NavCharHelper::GetNavigateIndexVal(sName.at(0))*100+1, LQFRIENDSLIST_ROLES::FRIENDINDEX_DATAS);

    pUserItem->setData(data.uOnlinesStatus!=5&&data.uOnlinesStatus!=0,LQFRIENDSLIST_ROLES::FRIENDONLINE_STATE);

    pUserItem->setData(QVariant::fromValue(data), LQFRIENDSLIST_ROLES::FRIENDSLIST_ITEMS);

    pListItemModel->appendRow(pUserItem);

    UpdateListDatas();

}

结束:由于整体代码很长,而篇幅有限,因此给个大概的思路和参考。在ListView中继承的Lncf_IndexNavListv我们将在后面的文章中给出,此类主要实现了列表导航封装。

有想一起学习或探讨的朋友可以留言或加QQ群:717743458

原创连接:C++ Qt开发社交好友列表_qtc++添加账户列表设计-CSDN博客

————————————————

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 221,273评论 6 515
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,349评论 3 398
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,709评论 0 360
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,520评论 1 296
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,515评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,158评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,755评论 3 421
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,660评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,203评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,287评论 3 340
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,427评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,122评论 5 349
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,801评论 3 333
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,272评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,393评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,808评论 3 376
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,440评论 2 359

推荐阅读更多精彩内容