C++,Qt开发社交软件会话列表控件

会话列表基于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);

篇幅太长,有关实现代码暂时不写了,如果后期有时间在补一部分重要代码

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

  • 0
    点赞
  • 1
    收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:深蓝海洋 设计师:CSDN官方博客 返回首页
评论

打赏作者

荒野山人

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值