Qt之实现好友列表

  • Post author:
  • Post category:其他



转载地址:  http://blog.csdn.net/u010519432/article/details/26988515


一直都认为,用最通俗的语言,讲解最深刻的技术,是每一个技术交流者应该考虑的事情,今天朋友问我,好友列表该怎么实现。我想起之前上网查阅的时候,发现网上介绍这块的内容甚少,而且讲解的不够好,于是,本着互相交流的精神,在这里讲解一下我是怎么实现QQ好友列表的。



1、




Q:



关于好友列表到底是QTreeWidget/QTreeView还是QListWidget/QListView的问题?



A:

相信大家初次一看,大部分都认为是QTreeWidget,其实是用QListWidget或者QListView均可简单实现,在数据多的时候,QListWidget性能会降低,不过,对于好友列表来说,QListWidget足以,并且更加简单。所以,我继承的是QListWidget来实现。



2、




Q:



关于如何实现一个Item具有多种信息,包括头像、用户名、个性签名等?



A:

该Item其实是一个继承了QWidget的自定义buddy类,把你所想要的信息全部在该buddy类里面布局好,甚至可以加进按钮,自定义的好处就在于,你想到什么,就能干什么,然后在QListWiget里面里通过实现

  1. QListWidgetItem *newItem =

    new

    QListWidgetItem();

    //创建一个newItem

  2. this

    ->insertItem(row(currentItem)+tem.count(),newItem);

    //将该newItem插入到后面

  3. this

    ->setItemWidget(newItem, buddy);

    //将buddy赋给该newItem

QListWidgetItem *newItem = new QListWidgetItem();       //创建一个newItem
this->insertItem(row(currentItem)+tem.count(),newItem); //将该newItem插入到后面
this->setItemWidget(newItem, buddy); //将buddy赋给该newItem


即可。



3、




Q:



关于如何实现好友的展开与隐藏?



A:

这部分里我设置了两个容器:

  1. QMap<QListWidgetItem*,QListWidgetItem*> groupMap;

    // 组容器 – key:项 value:组
  2. QMap<QListWidgetItem*,

    bool

    > isHideMap;

    //用来判断该组是否隐藏了

 QMap<QListWidgetItem*,QListWidgetItem*> groupMap;   // 组容器 - key:项 value:组
 QMap<QListWidgetItem*,bool> isHideMap;//用来判断该组是否隐藏了


其中,groupMap用来存放key为项,value为组的数据,比如我增加了一个“我的好友”的组,则存进去是key:我的好友,value:我的好友;接着,在isHideMap存放key:我的好友,value:false,表示默认该组是未展开的;紧接着,如果在“我的好友”里,我增加了一个好友“逍遥圣帝”,则存进去的是:key:逍遥圣帝,value:我的好友,这样处理的关键是为了保存好组与好友的关系;最后再利用isHideMap来判断组的状态,如果是隐藏,则通过遍历groupMap里面的好友,使之显示,否则,反之。



4、




Q:



关于如何实现美化效果?



A:

直接用QSS就可以了。


下面直接贴出源代码,我已经在源代码里面详细给每一个关键步骤进行了说明,所以就不进行阐述了,相信大家看得懂的,如有不懂可以追加评论,第一时间回复你们,下面是实现一个QQ好友列表的简单功能,对于其他功能大家好好拓展即可~~





一、首先是实现具有各种信息的Buddy类:

personListBuddy.h


  1. #ifndef PERSONLISTBUDDY_H

  2. #define PERSONLISTBUDDY_H

  3. #include <QWidget>

  4. #include <QLabel>

  5. #include <QEvent>

  6. //自定义信息Item类

  7. class

    personListBuddy :

    public

    QWidget
  8. {
  9. Q_OBJECT

  10. public

    :

  11. explicit

    personListBuddy(QWidget *parent = 0);

  12. void

    initUi();

    //初始化Ui
  13. QWidget *head;

    //头像
  14. QLabel *name;

    //用户名
  15. QLabel *sign;

    //个性签名
  16. QString headPath;

    //头像路径

  17. bool

    eventFilter(QObject *obj, QEvent *event);

    //事件过滤器
  18. signals:

  19. public

    slots:
  20. };

  21. #endif // PERSONLISTBUDDY_H

#ifndef PERSONLISTBUDDY_H
#define PERSONLISTBUDDY_H
#include <QWidget>
#include <QLabel>
#include <QEvent>
//自定义信息Item类
class personListBuddy : public QWidget
{
    Q_OBJECT
public:
    explicit personListBuddy(QWidget *parent = 0);
    void initUi();//初始化Ui
    QWidget *head;  //头像
    QLabel *name;  //用户名
    QLabel *sign;  //个性签名
    QString headPath;//头像路径
    bool eventFilter(QObject *obj, QEvent *event);//事件过滤器
    
signals:
    
public slots:
    
};
#endif // PERSONLISTBUDDY_H

personListBuddy.cpp


  1. #include “personlistbuddy.h”

  2. #include <QPainter>
  3. personListBuddy::personListBuddy(QWidget *parent) :
  4. QWidget(parent)
  5. {
  6. initUi();
  7. }

  8. //初始化Ui

  9. void

    personListBuddy::initUi()
  10. {

  11. //初始化
  12. head=

    new

    QWidget(

    this

    );
  13. name=

    new

    QLabel(

    this

    );
  14. sign=

    new

    QLabel(

    this

    );

  15. //设置头像大小
  16. head->setFixedSize(40,40);

  17. //设置个性签名字体为灰色
  18. QPalette color;
  19. color.setColor(QPalette::Text,Qt::gray);
  20. sign->setPalette(color);

  21. //布局
  22. head->move(7,7);
  23. name->move(54,10);
  24. sign->move(54,27);

  25. //装载事件过滤器
  26. head->installEventFilter(

    this

    );
  27. }

  28. //事件过滤器,主要是为了让图片能够全部填充在head里面

  29. bool

    personListBuddy::eventFilter(QObject *obj, QEvent *event)
  30. {

  31. if

    (obj == head)
  32. {

  33. if

    (event->type() == QEvent::Paint)
  34. {
  35. QPainter painter(head);
  36. painter.drawPixmap(head->rect(), QPixmap(headPath));
  37. }
  38. }

  39. return

    QWidget::eventFilter(obj, event);
  40. }

#include "personlistbuddy.h"
#include <QPainter>
personListBuddy::personListBuddy(QWidget *parent) :
    QWidget(parent)
{
    initUi();
}
//初始化Ui
void personListBuddy::initUi()
{
    //初始化
    head=new QWidget(this);
    name=new QLabel(this);
    sign=new QLabel(this);
    //设置头像大小
    head->setFixedSize(40,40);
    //设置个性签名字体为灰色
    QPalette color;
    color.setColor(QPalette::Text,Qt::gray);
    sign->setPalette(color);
    //布局
    head->move(7,7);
    name->move(54,10);
    sign->move(54,27);
    //装载事件过滤器
    head->installEventFilter(this);
}
//事件过滤器,主要是为了让图片能够全部填充在head里面
bool personListBuddy::eventFilter(QObject *obj, QEvent *event)
{
    if(obj == head)
    {
        if(event->type() == QEvent::Paint)
        {
            QPainter painter(head);
            painter.drawPixmap(head->rect(), QPixmap(headPath));
        }
    }
    return QWidget::eventFilter(obj, event);
}



二、实现好友列表personList类:

personList.h


  1. #ifndef PERSONLIST_H

  2. #define PERSONLIST_H

  3. #include <QListWidget>

  4. #include <QMenu>

  5. #include <QMouseEvent>

  6. #include <QLineEdit>

  7. //自定义QListWidget

  8. class

    personList :

    public

    QListWidget

    //继承QListWidget,可以使用它本身自带的函数,更方便
  9. {
  10. Q_OBJECT

  11. public

    :

  12. explicit

    personList(QListWidget *parent = 0);

  13. void

    mousePressEvent(QMouseEvent *event);

    //鼠标点击事件

  14. void

    contextMenuEvent(QContextMenuEvent*);

    //菜单事件,为了显示菜单

  15. void

    initMenu();

    //初始化菜单
  16. QMenu *blankMenu;

    //点击空白上的菜单
  17. QMenu *groupMenu;

    //点击组上的菜单
  18. QMenu *personMenu;

    //点击人上的菜单
  19. QMap<QListWidgetItem*,QListWidgetItem*> groupMap;

    // 组容器 – key:项 value:组
  20. QMap<QListWidgetItem*,

    bool

    > isHideMap;

    //用来判断该组是否隐藏了
  21. QLineEdit *groupNameEdit;

    //组的名字,重命名的时候需要用到
  22. QListWidgetItem *currentItem;

    //当前的项
  23. signals:

  24. public

    slots:

  25. void

    slotAddGroup();

    //添加组

  26. void

    slotDelGroup();

    //删除组

  27. void

    slotAddBuddy();

    //添加好友

  28. void

    slotDelBuddy();

    //删除好友

  29. void

    slotRename();

    //重命名组

  30. void

    slotRenameEditFshed();

    //命名完成
  31. };

  32. #endif // PERSONLIST_H

#ifndef PERSONLIST_H
#define PERSONLIST_H
#include <QListWidget>
#include <QMenu>
#include <QMouseEvent>
#include <QLineEdit>
//自定义QListWidget
class personList : public QListWidget //继承QListWidget,可以使用它本身自带的函数,更方便
{
    Q_OBJECT
public:
    explicit personList(QListWidget *parent = 0);
    void mousePressEvent(QMouseEvent *event);//鼠标点击事件
    void contextMenuEvent(QContextMenuEvent*);//菜单事件,为了显示菜单
    void initMenu();//初始化菜单
    QMenu *blankMenu;//点击空白上的菜单
    QMenu *groupMenu;//点击组上的菜单
    QMenu *personMenu;//点击人上的菜单
    QMap<QListWidgetItem*,QListWidgetItem*> groupMap;   // 组容器 - key:项 value:组
    QMap<QListWidgetItem*,bool> isHideMap;//用来判断该组是否隐藏了
    QLineEdit *groupNameEdit;//组的名字,重命名的时候需要用到
    QListWidgetItem *currentItem;//当前的项
    
signals:
    
public slots:
    void slotAddGroup();   //添加组
    void slotDelGroup();   //删除组
    void slotAddBuddy();   //添加好友
    void slotDelBuddy();   //删除好友
    void slotRename();     //重命名组
    void slotRenameEditFshed();//命名完成
    
};
#endif // PERSONLIST_H


personList.cpp


  1. #include “personlist.h”

  2. #include <QAction>

  3. #include <QIcon>

  4. #include “personlistbuddy.h”
  5. personList::personList(QListWidget *parent) :
  6. QListWidget(parent)
  7. {
  8. setFocusPolicy(Qt::NoFocus);

    // 去除item选中时的虚线边框
  9. setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);

    //水平滚动条关闭
  10. initMenu();
  11. }

  12. //初始化菜单

  13. void

    personList::initMenu()
  14. {

  15. //初始化:
  16. blankMenu =

    new

    QMenu();
  17. groupMenu =

    new

    QMenu();
  18. personMenu =

    new

    QMenu();
  19. groupNameEdit=

    new

    QLineEdit();
  20. QAction *addGroup =

    new

    QAction(

    “添加分组”

    ,

    this

    );
  21. QAction *delGroup =

    new

    QAction(

    “删除该组”

    ,

    this

    );
  22. QAction *rename =

    new

    QAction(

    “重命名”

    ,

    this

    );
  23. QAction *addBuddy =

    new

    QAction(

    “添加好友”

    ,

    this

    );
  24. QAction *delBuddy =

    new

    QAction(

    “删除好友”

    ,

    this

    );

  25. //设置:
  26. groupNameEdit->setParent(

    this

    );

    //设置父类
  27. groupNameEdit->hide();

    //设置初始时隐藏
  28. groupNameEdit->setPlaceholderText(

    “未命名”

    );

    //设置初始时的内容

  29. //布局:
  30. blankMenu->addAction(addGroup);
  31. groupMenu->addAction(delGroup);
  32. groupMenu->addAction(rename);
  33. groupMenu->addAction(addBuddy);
  34. personMenu->addAction(delBuddy);

  35. //信息槽:
  36. connect(groupNameEdit,SIGNAL(editingFinished()),

    this

    ,SLOT(slotRenameEditFshed()));
  37. connect(addGroup,SIGNAL(triggered()),

    this

    ,SLOT(slotAddGroup()));
  38. connect(delGroup,SIGNAL(triggered()),

    this

    ,SLOT(slotDelGroup()));
  39. connect(rename,SIGNAL(triggered()),

    this

    ,SLOT(slotRename()));
  40. connect(addBuddy,SIGNAL(triggered()),

    this

    ,SLOT(slotAddBuddy()));
  41. connect(delBuddy,SIGNAL(triggered()),

    this

    ,SLOT(slotDelBuddy()));
  42. }

  43. //鼠标点击事件

  44. void

    personList::mousePressEvent(QMouseEvent *event)
  45. {
  46. QListWidget::mousePressEvent(event);

    // 如果不调用基类mousePressEvent,item被select会半天不响应,调用父类,让QSS起效,因为QSS基于父类QListWidget,子类就是子窗口,就是最上层窗口,是覆盖在父窗口上的,所以先于父窗口捕获消息

  47. //防止一种特殊情况:给新item命名、点击其他item或空白处时,指向新item的currentItem被赋予其他item

  48. if

    (groupNameEdit->isVisible() && !(groupNameEdit->rect().contains(event->pos())))
  49. {

  50. if

    (groupNameEdit->text()!=NULL)
  51. currentItem->setText(groupNameEdit->text());
  52. groupNameEdit->setText(

    “”

    );
  53. groupNameEdit->hide();
  54. }
  55. currentItem =

    this

    ->itemAt(mapFromGlobal(QCursor::pos()));

    //鼠标位置的Item,不管右键左键都获取

  56. if

    (event->button()==Qt::LeftButton && currentItem!=NULL && currentItem==groupMap.value(currentItem))

    //如果点击的左键并且是点击的是组
  57. {

  58. if

    (isHideMap.value(currentItem))

    //如果先前是隐藏,则显示
  59. {
  60. foreach(QListWidgetItem* subItem, groupMap.keys(currentItem))

    //遍历组的对应的项(包括自身和好友)

  61. if

    (subItem!=currentItem)

    //如果是组的话不进行处理
  62. {
  63. subItem->setHidden(

    false

    );

    //好友全部显示
  64. }
  65. isHideMap.insert(currentItem,

    false

    );

    //设置该组为显示状态
  66. currentItem->setIcon(QIcon(

    “:/arrowDown”

    ));
  67. }

  68. else


    //否则,先前是显示,则隐藏
  69. {
  70. foreach(QListWidgetItem* subItem, groupMap.keys(currentItem))

    //遍历组的对应的项(包括自身和好友)

  71. if

    (subItem!=currentItem)

    //如果是组的话不进行处理
  72. {
  73. subItem->setHidden(

    true

    );

    //好友全部隐藏
  74. }
  75. isHideMap.insert(currentItem,

    true

    );

    //设置该组为隐藏状态
  76. currentItem->setIcon(QIcon(

    “:/arrowRight”

    ));
  77. }
  78. }
  79. }

  80. //菜单事件,为了显示菜单,点击鼠标右键响应,鼠标点击事件mousePressEvent优先于contextMenuEvent

  81. void

    personList::contextMenuEvent(QContextMenuEvent *event)
  82. {
  83. QListWidget::contextMenuEvent(event);

    //调用基类事件

  84. if

    (currentItem==NULL)

    //如果点击到的是空白处
  85. {
  86. blankMenu->exec(QCursor::pos());

  87. return

    ;
  88. }

  89. if

    (currentItem==groupMap.value(currentItem))

    // 如果点击到的是组
  90. groupMenu->exec(QCursor::pos());

  91. else


    //否则点击到的是好友
  92. personMenu->exec(QCursor::pos());
  93. }

  94. //添加组

  95. void

    personList::slotAddGroup()
  96. {
  97. QListWidgetItem *newItem=

    new

    QListWidgetItem(QIcon(

    “:/arrowRight”

    ),

    “未命名”

    );

    //创建一个Item
  98. newItem->setSizeHint(QSize(

    this

    ->width(),25));

    //设置宽度、高度

  99. this

    ->addItem(newItem);

    //加到QListWidget中
  100. groupMap.insert(newItem,newItem);

    //加到容器groupMap里,key和value都为组
  101. isHideMap.insert(newItem,

    true

    );

    //设置该组隐藏状态
  102. groupNameEdit->raise();
  103. groupNameEdit->setText(tr(

    “未命名”

    ));

    //设置默认内容
  104. groupNameEdit->selectAll();

    //设置全选
  105. groupNameEdit->setGeometry(

    this

    ->visualItemRect(newItem).left()+15,

    this

    ->visualItemRect(newItem).top()+1,

    this

    ->visualItemRect(newItem).width(),

    this

    ->visualItemRect(newItem).height()-2);

    //出现的位置
  106. groupNameEdit->show();

    //显示
  107. groupNameEdit->setFocus();

    //获取焦点
  108. currentItem = newItem;

    // 因为要给group命名,所以当前的currentItem设为该group
  109. }

  110. //删除组

  111. void

    personList::slotDelGroup()
  112. {
  113. foreach(QListWidgetItem* item, groupMap.keys(currentItem))

    //遍历该组的所有好友和自身的组
  114. {
  115. groupMap.remove(item);

    //移除

  116. delete

    item;

    //删除
  117. }
  118. isHideMap.remove(currentItem);

    //移除
  119. }

  120. //重命名

  121. void

    personList::slotRename()
  122. {
  123. groupNameEdit->raise();
  124. groupNameEdit->setGeometry(

    this

    ->visualItemRect(currentItem).left()+15,

    this

    ->visualItemRect(currentItem).top()+1,

    this

    ->visualItemRect(currentItem).width(),

    this

    ->visualItemRect(currentItem).height()-2);

    //出现的位置
  125. groupNameEdit->setText(currentItem->text());

    //获取该组名内容
  126. groupNameEdit->show();

    //显示
  127. groupNameEdit->selectAll();

    //全选
  128. groupNameEdit->setFocus();

    //获取焦点
  129. }

  130. //添加好友,主要是为了测试功能,实际工程里可以改成动态读取数据库进行添加好友

  131. void

    personList::slotAddBuddy()
  132. {
  133. personListBuddy *buddy=

    new

    personListBuddy();

    //创建一个自己定义的信息类
  134. buddy->headPath=

    “:/head”

    ;

    //设置头像路径
  135. buddy->name->setText(

    “逍遥圣帝”

    );

    //设置用户名
  136. buddy->sign->setText(

    “用通俗的语言,讲深刻的技术。”

    );

    //设置个性签名
  137. QList<QListWidgetItem*> tem = groupMap.keys(currentItem);

    //当前组对应的项(包括组本身和好友)复制给tem

  138. //关键代码
  139. QListWidgetItem *newItem =

    new

    QListWidgetItem();

    //创建一个newItem

  140. this

    ->insertItem(row(currentItem)+tem.count(),newItem);

    //将该newItem插入到后面

  141. this

    ->setItemWidget(newItem, buddy);

    //将buddy赋给该newItem
  142. groupMap.insert(newItem,currentItem);

    //加进容器,key为好友,value为组

  143. if

    (isHideMap.value(currentItem))

    //如果该组是隐藏,则加进去的好友设置为隐藏
  144. newItem->setHidden(

    true

    );

  145. else


    //否则,该好友设置为显示
  146. newItem->setHidden(

    false

    );
  147. }

  148. //删除好友

  149. void

    personList::slotDelBuddy()
  150. {
  151. groupMap.remove(currentItem);

    //移除该好友

  152. delete

    currentItem;

    //删除
  153. }

  154. //重命名完成

  155. void

    personList::slotRenameEditFshed()
  156. {

  157. if

    (groupNameEdit->text()!=NULL)

    //如果重命名编辑框不为空
  158. currentItem->setText(groupNameEdit->text());

    //更新组名
  159. groupNameEdit->setText(

    “”

    );
  160. groupNameEdit->hide();

    //隐藏重命名编辑框
  161. }

#include "personlist.h"
#include <QAction>
#include <QIcon>
#include "personlistbuddy.h"
personList::personList(QListWidget *parent) :
    QListWidget(parent)
{
    setFocusPolicy(Qt::NoFocus);       // 去除item选中时的虚线边框
    setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);//水平滚动条关闭
    initMenu();
}
//初始化菜单
void personList::initMenu()
{
    //初始化:
    blankMenu = new QMenu();
    groupMenu = new QMenu();
    personMenu = new QMenu();
    groupNameEdit=new QLineEdit();
    QAction *addGroup = new QAction("添加分组", this);
    QAction *delGroup = new QAction("删除该组", this);
    QAction *rename = new QAction("重命名", this);
    QAction *addBuddy = new QAction("添加好友",this);
    QAction *delBuddy = new QAction("删除好友", this);
    //设置:
    groupNameEdit->setParent(this);  //设置父类
    groupNameEdit->hide(); //设置初始时隐藏
    groupNameEdit->setPlaceholderText("未命名");//设置初始时的内容
    //布局:
    blankMenu->addAction(addGroup);
    groupMenu->addAction(delGroup);
    groupMenu->addAction(rename);
    groupMenu->addAction(addBuddy);
    personMenu->addAction(delBuddy);
    //信息槽:
    connect(groupNameEdit,SIGNAL(editingFinished()),this,SLOT(slotRenameEditFshed()));
    connect(addGroup,SIGNAL(triggered()),this,SLOT(slotAddGroup()));
    connect(delGroup,SIGNAL(triggered()),this,SLOT(slotDelGroup()));
    connect(rename,SIGNAL(triggered()),this,SLOT(slotRename()));
    connect(addBuddy,SIGNAL(triggered()),this,SLOT(slotAddBuddy()));
    connect(delBuddy,SIGNAL(triggered()),this,SLOT(slotDelBuddy()));
}
//鼠标点击事件
void personList::mousePressEvent(QMouseEvent *event)
{
    QListWidget::mousePressEvent(event); // 如果不调用基类mousePressEvent,item被select会半天不响应,调用父类,让QSS起效,因为QSS基于父类QListWidget,子类就是子窗口,就是最上层窗口,是覆盖在父窗口上的,所以先于父窗口捕获消息
    //防止一种特殊情况:给新item命名、点击其他item或空白处时,指向新item的currentItem被赋予其他item
    if(groupNameEdit->isVisible() && !(groupNameEdit->rect().contains(event->pos())))
    {
        if(groupNameEdit->text()!=NULL)
            currentItem->setText(groupNameEdit->text());
        groupNameEdit->setText("");
        groupNameEdit->hide();
    }
    currentItem = this->itemAt(mapFromGlobal(QCursor::pos()));//鼠标位置的Item,不管右键左键都获取
    if(event->button()==Qt::LeftButton && currentItem!=NULL && currentItem==groupMap.value(currentItem))//如果点击的左键并且是点击的是组
    {
        if(isHideMap.value(currentItem))                                  //如果先前是隐藏,则显示
        {
            foreach(QListWidgetItem* subItem, groupMap.keys(currentItem))//遍历组的对应的项(包括自身和好友)
                if(subItem!=currentItem)                                 //如果是组的话不进行处理
                {
                    subItem->setHidden(false);                            //好友全部显示
                }
            isHideMap.insert(currentItem,false);                          //设置该组为显示状态
            currentItem->setIcon(QIcon(":/arrowDown"));
        }
        else                                                             //否则,先前是显示,则隐藏
        {
            foreach(QListWidgetItem* subItem, groupMap.keys(currentItem))//遍历组的对应的项(包括自身和好友)
                if(subItem!=currentItem)                                 //如果是组的话不进行处理
                {
                    subItem->setHidden(true);                            //好友全部隐藏
                }
             isHideMap.insert(currentItem,true);                          //设置该组为隐藏状态
             currentItem->setIcon(QIcon(":/arrowRight"));
        }
    }
}
//菜单事件,为了显示菜单,点击鼠标右键响应,鼠标点击事件mousePressEvent优先于contextMenuEvent
void personList::contextMenuEvent(QContextMenuEvent *event)
{
    QListWidget::contextMenuEvent(event);           //调用基类事件
    if(currentItem==NULL)                           //如果点击到的是空白处
    {
        blankMenu->exec(QCursor::pos());
        return;
    }
    if(currentItem==groupMap.value(currentItem))    // 如果点击到的是组
        groupMenu->exec(QCursor::pos());
    else                                            //否则点击到的是好友
        personMenu->exec(QCursor::pos());
}
//添加组
void personList::slotAddGroup()
{
    QListWidgetItem *newItem=new QListWidgetItem(QIcon(":/arrowRight"),"未命名");    //创建一个Item
    newItem->setSizeHint(QSize(this->width(),25));//设置宽度、高度
    this->addItem(newItem);         //加到QListWidget中
    groupMap.insert(newItem,newItem);//加到容器groupMap里,key和value都为组
    isHideMap.insert(newItem,true);  //设置该组隐藏状态
    groupNameEdit->raise();
    groupNameEdit->setText(tr("未命名")); //设置默认内容
    groupNameEdit->selectAll();        //设置全选
    groupNameEdit->setGeometry(this->visualItemRect(newItem).left()+15,this->visualItemRect(newItem).top()+1,this->visualItemRect(newItem).width(),this->visualItemRect(newItem).height()-2);//出现的位置
    groupNameEdit->show();              //显示
    groupNameEdit->setFocus();          //获取焦点
    currentItem = newItem;	   // 因为要给group命名,所以当前的currentItem设为该group
}
//删除组
void personList::slotDelGroup()
{
    foreach(QListWidgetItem* item, groupMap.keys(currentItem))  //遍历该组的所有好友和自身的组
    {
        groupMap.remove(item);   //移除
        delete item;   //删除
    }
    isHideMap.remove(currentItem); //移除
}
//重命名
void personList::slotRename()
{
    groupNameEdit->raise();
    groupNameEdit->setGeometry(this->visualItemRect(currentItem).left()+15,this->visualItemRect(currentItem).top()+1,this->visualItemRect(currentItem).width(),this->visualItemRect(currentItem).height()-2);//出现的位置
    groupNameEdit->setText(currentItem->text());   //获取该组名内容
    groupNameEdit->show();                        //显示
    groupNameEdit->selectAll();                   //全选
    groupNameEdit->setFocus();                        //获取焦点
}
//添加好友,主要是为了测试功能,实际工程里可以改成动态读取数据库进行添加好友
void personList::slotAddBuddy()
{
    personListBuddy *buddy=new personListBuddy();   //创建一个自己定义的信息类
    buddy->headPath=":/head";                          //设置头像路径
    buddy->name->setText("逍遥圣帝");                  //设置用户名
    buddy->sign->setText("用通俗的语言,讲深刻的技术。");   //设置个性签名
    QList<QListWidgetItem*> tem = groupMap.keys(currentItem);//当前组对应的项(包括组本身和好友)复制给tem
    //关键代码
    QListWidgetItem *newItem = new QListWidgetItem();       //创建一个newItem
    this->insertItem(row(currentItem)+tem.count(),newItem); //将该newItem插入到后面
    this->setItemWidget(newItem, buddy); //将buddy赋给该newItem
    groupMap.insert(newItem,currentItem);   //加进容器,key为好友,value为组
    if(isHideMap.value(currentItem))          //如果该组是隐藏,则加进去的好友设置为隐藏
        newItem->setHidden(true);
    else                                      //否则,该好友设置为显示
        newItem->setHidden(false);
}
//删除好友
void personList::slotDelBuddy()
{
    groupMap.remove(currentItem);  //移除该好友
    delete currentItem;            //删除
}
//重命名完成
void personList::slotRenameEditFshed()
{
    if(groupNameEdit->text()!=NULL)      //如果重命名编辑框不为空
        currentItem->setText(groupNameEdit->text());  //更新组名
    groupNameEdit->setText("");
    groupNameEdit->hide();  //隐藏重命名编辑框
}




三、美化用到的QSS:

  1. QListWidget{
  2. background:white;
  3. color:black;
  4. border:none;
  5. }
  6. QListWidget::item{
  7. border:none;
  8. height: 54px;
  9. }
  10. QListWidget::item:hover{
  11. background:rgb(252,240,193)
  12. }
  13. QListWidget::item:selected{
  14. background:rgb(252,233,161);
  15. color:black;
  16. }
  17. QScrollBar:vertical {
  18. background:transparent;
  19. width:9px;
  20. margin: 0px 0px 2px 0px;
  21. }
  22. QScrollBar::handle:vertical {
  23. background: rgb(195, 195, 195);
  24. min-height: 20px;
  25. border-radius: 3px;
  26. }
  27. QScrollBar::handle:vertical:hover{
  28. background:rgba(0,0,0,30%);
  29. }
  30. QScrollBar::add-line:vertical {
  31. height: 0px;
  32. subcontrol-position: bottom;
  33. subcontrol-origin: margin;
  34. }
  35. QScrollBar::sub-line:vertical {
  36. height: 0px;
  37. subcontrol-position: top;
  38. subcontrol-origin: margin;
  39. }

QListWidget{
	background:white;
	color:black;
	border:none;
}

QListWidget::item{
	border:none;
        height: 54px;
}

QListWidget::item:hover{
    background:rgb(252,240,193)
}

QListWidget::item:selected{
	background:rgb(252,233,161);
	color:black;
}

QScrollBar:vertical {               
    background:transparent;
    width:9px;
    margin: 0px 0px 2px 0px;
}

QScrollBar::handle:vertical {
    background: rgb(195, 195, 195);
    min-height: 20px;
    border-radius: 3px;
}

QScrollBar::handle:vertical:hover{
    background:rgba(0,0,0,30%);
}

QScrollBar::add-line:vertical {
    height: 0px;
    subcontrol-position: bottom;
    subcontrol-origin: margin;
}

QScrollBar::sub-line:vertical {
    height: 0px;
    subcontrol-position: top;
    subcontrol-origin: margin;
}



四、用到的素材:






五、效果图: